Android自定义随手势滑动的滚动条实现——HorizontalScrollCursor

从早上开始撸到现在撸了一个小组件HorizontalScrollCursor,废话不多说先上效果预览图

下面是在项目中的预览图:

  

QAQ看起来还是很Nice滴。之前写的一个下滑条是能实现跟随Viewpager移动到指定的下标下面,但是不能随着手指拖动而滑动,所以这个控件的实现目的就在于此。

项目以及上传到Github,克隆地址为: 点击打开链接

功能简介:

1:实现了随手势滑动滑动条。

2:做了简单的封装,将间距(每个滑动位置之间的宽度)以及滑动条颜色自定义为可在XML中设置的属性。

3:在该类的内部实现了回调接口onViewPagerChanggedListner,设置了setcallback(Activity activity)方法可将实现了该接口的Activity传进去以实现随着目录改变对其他UI(比如上面的选项按钮)的更新。


使用方法:

总的步骤很简单只有三步:设置布局,设置回调接口,设置Viewpager。

下面是详细步骤:

首先在布局文件中设置自定义的属性以及默认宽高:

   <com.whale.nangua.gestureslide.HorizontalScrollCursor
        xmlns:cursor="http://schemas.android.com/apk/res/com.whale.nangua.gestureslide"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        cursor:cursorcolor = "#ef0bef"
        cursor:space = "60"
        android:id="@+id/title"
        />
然后将Activity继承HorizontalScrollCursor的接口:

public class MainActivity extends FragmentActivity implements HorizontalScrollCursor.onViewPagerChanggedListner{
实现接口的方法:

  @Override
    public void CheckPage(int position) {
        //这里实现对其他UI的更新
    }

最后再对HorizontalScrollCursor进行初始化以及设置回调接口与Viewpager

        HorizontalScrollCursor cursor = (HorizontalScrollCursor) findViewById(R.id.title);
        cursor.setcallback(this);
        cursor.setViewPager(mViewPager);

这里要注意传入的Viewpager是在HorizontalScrollCursor内部实现了监听,不要再到其他地方写该Viewpager的监听事件以免发生冲突!



实现解析:

建议先看完最后粘贴出来的HorizontalScrollCursor类源码再来看这里!

实现下滑条随手势滑动的原理很简单,就是在draw中不断测量滑条的位置并不断进行重绘,那么最关键的是下面这个测量的方法:

   /**
     * 测量下划线的位置
     */
    private void measureLineSize(){
        lineStartX = strX[lastPosition]   + (DEFAULT_CURSOR_WIDTH   )* lineScale + space/2;
        if ((lastPosition + 1) == mViewPager.getAdapter().getCount()) {
            lineEndX = strX[lastPosition] + DEFAULT_CURSOR_WIDTH   - space/2;
        }else {
            lineEndX = strX[lastPosition] + DEFAULT_CURSOR_WIDTH   + (DEFAULT_CURSOR_WIDTH  ) * lineScale - space/2;
        }
    }
方法中的关键字依次为:

lineStartX:滑条左侧位置点

lineEndX:滑条右侧位置点

lastPosition:滑条滚到的位置,strX[]数组数据如下,可以看到依次为下滑条宽度的倍数:

       for (int i = 0;i<count;i++) {
            strX[i] = DEFAULT_CURSOR_WIDTH*i ;
        }
space:间隔

lineScale :在onPageScrolled()方法中的第二个变量positionOffset处获取,为当前滑动页面的偏移百分比
如下图所以可以很好的解释它们之间の关系(画的很挫见谅..):


可以看出:

1、可以看到在每个固定点位置,startX都往右偏移了space/2的距离,而endX都往左偏移了space/2的距离。

2、在滑动过程中,位移量应该为width*lineScale :宽度乘以滑动的百分比来计算得出。

3、每到一个固定点要对之前得位置距离进行累加。

搞懂了这三点,就能清楚地理解measureLineSize方法的实现了。

最后附上HorizontalScrollCursor实现代码:

 package com.whale.nangua.gestureslide;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * Created by nangua on 2016/5/21.
 */
public class HorizontalScrollCursor extends View implements ViewPager.OnPageChangeListener{
    private Context context;
    //传入的Viewpager
    private ViewPager mViewPager;
    private float lineStartX;
    private int lastPosition = 0 ;
    private float lineScale = 0 ; //Page移动的比例
    private float lineEndX = 0  ;
    //在XML中设定的参数
    private int width = 0;//控件总宽度
    private int height = 0;//控件总高度
    private int padingLeft = 0;//设置的padingLeft
    private int padingRight = 0;//设置的padingRight

    //间隔
    private int space   ;//默认为0
    //指定的页面个数
    private int count = 0;//!!!这里后面应该改为set方法得到

    //Cursor的画笔
    private Paint linePaint;

    //测量参数
    private void measureSize(){
        width = getWidth(); //得到宽度
        DEFAULT_CURSOR_WIDTH = width/count ;
        strX  = new float[count];
        for (int i = 0;i<count;i++) {
            strX[i] = DEFAULT_CURSOR_WIDTH*i ;
        }


        height = getHeight();//得到设定的高度
        padingLeft = getPaddingLeft();   //得到的是40
        padingRight = getPaddingRight();  //得到padingRight
    }

    private int DEFAULT_CURSOR_WIDTH  ;//默认游标宽度
    private float [] strX  ;

    /**
     * 测量下划线的位置
     */
    private void measureLineSize(){
        lineStartX = strX[lastPosition]   + (DEFAULT_CURSOR_WIDTH   )* lineScale + space/2;
        if ((lastPosition + 1) == mViewPager.getAdapter().getCount()) {
            lineEndX = strX[lastPosition] + DEFAULT_CURSOR_WIDTH   - space/2;
        }else {
            lineEndX = strX[lastPosition] + DEFAULT_CURSOR_WIDTH   + (DEFAULT_CURSOR_WIDTH  ) * lineScale - space/2;
        }
    }


    /**
     * 初始化画笔
     * @param context
     * @param attrs
     */
    private void init(Context context, AttributeSet attrs){
        this.context = context ;
        TypedArray t = getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalScrollCursor);

        int cursorspace = t.getInt(R.styleable.HorizontalScrollCursor_space, 0);
        space = cursorspace;
        int cursorColor = t.getColor(R.styleable.HorizontalScrollCursor_cursorcolor, Color.BLACK);
        Log.d("nanguabaobeia" ,"" + cursorColor + "||" + cursorspace);
        t.recycle();
        linePaint = new Paint();
        linePaint.setColor(cursorColor);
        linePaint.setStyle(Paint.Style.FILL);
        linePaint.setStrokeWidth(80);
    }

    /**
     * 设置游标间距
     * @param space
     */
    public void setspace(int space){
        this.space = space ;
    }


    public HorizontalScrollCursor(Context context) {
        super(context);
    }

    public HorizontalScrollCursor(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    public HorizontalScrollCursor(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        measureSize();  //测量数值
        measureLineSize();//测量下划线的位置
        drawLine(canvas);//画下划线

    }

    private void drawLine(Canvas canvas){
        canvas.drawLine(lineStartX, height, lineEndX, height, linePaint);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        this.lastPosition = position ;
        lineScale = positionOffset ;

        invalidate();
    }

    @Override
    public void onPageSelected(int position) {

    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

    public void setViewPager(ViewPager mViewPager){
        this.mViewPager = mViewPager;
        if (this.mViewPager != null) {
            this.mViewPager.setOnPageChangeListener(this);
        }
        count = mViewPager.getAdapter().getCount();
    }


    //回调接口实例
    onViewPagerChanggedListner callback;

    public void setcallback(Activity activity) {
        callback = (onViewPagerChanggedListner) activity;
    }

    //回调接口
    public interface onViewPagerChanggedListner {
        void CheckPage(int position);
    }
}



评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值