Android RangeSeekBarView 选定范围值的控件

自定义实现了一个选定范围值的控件,刻度尺为等分的100等分。模仿二手车app中筛选选定区间的控件。


实现效果:


首先将这个控件分成四部分,位置标记,刻度,尺子,游标。

Android RangeSeekBarView 选定范围值的控件_第1张图片Android RangeSeekBarView 选定范围值的控件_第2张图片


一,测量子控件的尺度,继承onMeasure().由子空间的尺寸来确定控件的尺寸。

[java]  view plain  copy
 
  1. @Override  
  2. protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.     measureChildren(widthMeasureSpec,heightMeasureSpec);    //测量子控件  
  4.     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  5.   
  6.     int mWidth=MeasureSpec.getSize(widthMeasureSpec);  
  7.     proPaddingLeftAndRight=mThumbLeft.getMeasuredWidth()/2;  
  8.     mLeftLimit=proPaddingLeftAndRight;  
  9.     mRightLimit=mWidth-proPaddingLeftAndRight;  
  10.   
  11.     //位置标记的高度+尺子的刻度高度+尺子的高度+游标的高度  
  12.     setMeasuredDimension(mWidth,mThumbPlaceHeight+RULE_HEIGHT_PX+mProgressBarHeight+mThumbLeft.getMeasuredHeight());  
  13. }  

二,对控件进行布局。

由于游标需要去监听他的滑动事件,所以这里自定义一个游标控件ThumbView。

[java]  view plain  copy
 
  1. @Override  
  2.     protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  3.         int heightSum=0;  
  4.   
  5.         heightSum+=mThumbPlaceHeight;  
  6.   
  7.         heightSum+=RULE_HEIGHT_PX;  
  8.   
  9.         heightSum+=mProgressBarHeight;  
  10.   
  11.         mPartWidth=(mRightLimit-mLeftLimit)/(float)mMaxValue;   //计算一份所占的宽度  一定要用float  
  12.   
  13.         mThumbLeft.setLimit(mLeftLimit,mRightLimit);    //设置可以移动的范围  
  14.         mThumbLeft.layout(0,heightSum,mThumbLeft.getMeasuredWidth(),b-10);      //设置在父布局的位置  
  15.   
  16.         mThumbRight.setLimit(mLeftLimit,mRightLimit);  
  17.         mThumbRight.layout(0,heightSum,mThumbLeft.getMeasuredWidth(),b-10);  
  18.   
  19.         onLayoutPrepared();     //layout调用后调用的方法,比如设置thumb limit  
  20.     }  

三,绘制尺子,尺子的刻度,尺子上的位置标记控件。

绘制尺子,其中mProBaseline为尺子top的位置。尺子的range实际是两个不同的矩形框。

[java]  view plain  copy
 
  1. /** 
  2.     * 画尺子 
  3.     *@param canvas 
  4.     */  
  5.    protected void drawProgressBar(Canvas canvas){  
  6.        //画背景  
  7.        Paint paint=new Paint();  
  8.        paint.setAntiAlias(true);  
  9.        paint.setColor(getResources().getColor(R.color.grey));  
  10.        Rect rect=new Rect(mLeftLimit,mProBaseline,mRightLimit,mProBaseline+mProgressBarHeight);  
  11.        canvas.drawRect(rect,paint);  
  12.   
  13.        //画进度  
  14.        paint.setColor(getResources().getColor(R.color.blue));  
  15.        rect=new Rect(mThumbLeft.getCenterX(),mProBaseline,mThumbRight.getCenterX(),mProBaseline+mProgressBarHeight);  
  16.        canvas.drawRect(rect,paint);  
  17.    }  
绘制刻度,这里将尺子分成了100等分,然后前5份和后5份不画,中间部分每两份画一条线,每10份画一条长线。

[java]  view plain  copy
 
  1. protected void drawRule(Canvas canvas){  
  2.     Paint paint=new Paint();  
  3.     paint.setStrokeWidth(1);  
  4.     paint.setColor(getResources().getColor(R.color.grey));  
  5.     paint.setTextSize(20);  
  6.     paint.setTextAlign(Paint.Align.CENTER);  
  7.     paint.setAntiAlias(true);  
  8.   
  9.     //一次遍历两份,绘制的位置都是在奇数位置  
  10.     for(int i=5;i<=mMaxValue;i+=2){  
  11.         if(i<PART_ITEM||i>mMaxValue-PART_ITEM){  
  12.             continue;  
  13.         }  
  14.   
  15.   
  16.         float degX=mLeftLimit+i*mPartWidth;  
  17.         int degY;  
  18.   
  19.         if((i-PART_ITEM)%(PART_ITEM*2)==0){  
  20.             degY=mProBaseline-DensityUtil.dip2px(getContext(),LONGLINE_HEIGHT);  
  21.             canvas.drawText(degs[(i-5)/10]+unitStr,degX,degY,paint);    //画文字  
  22.         }else{  
  23.             degY=mProBaseline-DensityUtil.dip2px(getContext(),SHORTLINE_HEIGHT);  
  24.         }  
  25.         canvas.drawLine(degX,mProBaseline,degX,degY,paint);  
  26.     }  
  27. }  
绘制标记控件,根据游标ThumbView的isMoving属性来判断是否需要绘制标记数值。isMoving true绘制,false 不 绘制

[java]  view plain  copy
 
  1. /** 
  2.  * 画 Thumb 位置的数值(标记) 
  3.  */  
  4. protected void drawRodPlaceValue(Canvas canvas,ThumbView thumbView){  
  5.     int centerX=thumbView.getCenterX();  
  6.     Paint paint=new Paint();  
  7.     BitmapDrawable bd= (BitmapDrawable) mThumbPlaceDrawable;  
  8.     canvas.drawBitmap(bd.getBitmap(),centerX-mThumbPlaceDrawable.getIntrinsicWidth()/2,0,paint);  
  9.   
  10.     paint.setColor(Color.WHITE);  
  11.     paint.setTextAlign(Paint.Align.CENTER);  
  12.     paint.setTextSize(30);  
  13.     canvas.drawText(geneareThumbValue(thumbView)+"",centerX,mThumbDrawable.getIntrinsicHeight()/2,paint);  
  14. }  

四,相关计算

要根据游标在刻度尺上的位置,计算进度。


[java]  view plain  copy
 
  1. private int geneareThumbValue(ThumbView view){  
  2.     //todo 这里只是计算了100之多少的值,需要自行转换成刻度上的值  
  3.     int proValue=mMaxValue*(view.getCenterX()-mLeftLimit)/(mRightLimit-mLeftLimit);  
  4.     return proValue;  
  5. }  

五,游标控件 ThumbView

1,mLeftLimit, mRightLimit是游标能浮动的位置。

2,当Touch事件为move时,来改变自身的位置。

[java]  view plain  copy
 
  1. package com.jayce.uidefine;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Rect;  
  5. import android.util.AttributeSet;  
  6. import android.view.MotionEvent;  
  7. import android.widget.ImageView;  
  8.   
  9. /** 
  10.  * @author jayce 
  11.  * @date 2015/3/12 
  12.  */  
  13. public class ThumbView extends ImageView {  
  14.   
  15.     private RangeSeekBar rangeSeekBar;  
  16.   
  17.     private int mDownX=0;  
  18.     private int mWidth;  
  19.   
  20.     private int mLeftLimit=0;  
  21.     private int mRightLimit=Integer.MAX_VALUE;  
  22.   
  23.     private Rect rect;  
  24.   
  25.     private int mCenterX;   //游标的中心位置  
  26.   
  27.     private boolean mIsMoving;      //游标是否正在移动  
  28.   
  29.     private OnThumbListener listener;  
  30.   
  31.     public ThumbView(Context context) {  
  32.         this(context, null);  
  33.     }  
  34.   
  35.     public ThumbView(Context context, AttributeSet attrs) {  
  36.         this(context, attrs, 0);  
  37.     }  
  38.   
  39.     public ThumbView(Context context, AttributeSet attrs, int defStyleAttr) {  
  40.         super(context, attrs, defStyleAttr);  
  41.     }  
  42.   
  43.     public void setRangeSeekBar(RangeSeekBar rangeSeekBar) {  
  44.         this.rangeSeekBar = rangeSeekBar;  
  45.     }  
  46.   
  47.     public void setLimit(int mLeftLimit,int mRightLimit) {  
  48.         this.mLeftLimit = mLeftLimit;  
  49.         this.mRightLimit=mRightLimit;  
  50.     }  
  51.   
  52.     public int getCenterX() {  
  53.         return mCenterX;  
  54.     }  
  55.   
  56.     /** 
  57.      * 设置中心位置,不超过左右的limit,就刷新整个控件,并且回调onThumbChange() 
  58.      * @param centerX 
  59.      */  
  60.     public void setCenterX(int centerX) {  
  61.         int left=centerX-mWidth/2,right=centerX+mWidth/2;  
  62.         if(centerX<mLeftLimit) {  
  63.             left=mLeftLimit-mWidth/2;  
  64.             right=mLeftLimit+mWidth/2;  
  65.         }  
  66.   
  67.         if(centerX>mRightLimit){  
  68.             left=mRightLimit-mWidth/2;  
  69.             right=mRightLimit+mWidth/2;  
  70.         }  
  71.   
  72.         this.mCenterX = (left+right)/2;  
  73.   
  74.         if(left!=rect.left||right!=rect.right){  
  75.             rect.union(left,rect.top,right,rect.bottom);  
  76.             layout(left, rect.top, right, rect.bottom);  
  77.             //invalidate(rect);  
  78.             rangeSeekBar.invalidate();  
  79.   
  80.             if(listener!=null){  
  81.                 listener.onThumbChange(100*((left+right)/2-mLeftLimit)/(mRightLimit-mLeftLimit));  
  82.             }  
  83.         }  
  84.     }  
  85.   
  86.     public boolean isMoving() {  
  87.         return mIsMoving;  
  88.     }  
  89.   
  90.     public void setOnThumbListener(OnThumbListener listener) {  
  91.         this.listener = listener;  
  92.     }  
  93.   
  94.     @Override  
  95.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  96.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  97.   
  98.         mWidth=getMeasuredWidth();  
  99.     }  
  100.   
  101.     @Override  
  102.     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  103.         super.onLayout(changed, left, top, right, bottom);  
  104.   
  105.         rect=new Rect(left,top,right,bottom);  
  106.     }  
  107.   
  108.     @Override  
  109.     public boolean onTouchEvent(MotionEvent event) {  
  110.         switch (event.getAction()) {  
  111.             case MotionEvent.ACTION_DOWN:  
  112.                 mDownX = (int) event.getX();  
  113.                 mIsMoving=false;  
  114.   
  115.                 break;  
  116.             case MotionEvent.ACTION_MOVE:  
  117.                 int nowX = (int) event.getX();  
  118.   
  119.                 int left = rect.left + nowX - mDownX;  
  120.                 int right = rect.right + nowX - mDownX;  
  121.                 mIsMoving=true;  
  122.                 setCenterX((left+right)/2);  
  123.                 break;  
  124.             case MotionEvent.ACTION_UP:  
  125.                 mIsMoving=false;  
  126.                 rangeSeekBar.invalidate();  
  127.                 break;  
  128.         }  
  129.         return true;  
  130.     }  
  131.   
  132.     public interface OnThumbListener{  
  133.         public void onThumbChange(int i);  
  134.     }  
  135. }  


下载地址 http://download.csdn.net/detail/huweigoodboy/8508243


使用中的问题:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:orientation="vertical">

    </LinearLayout>

    <com.jayce.uidefine.RangeSeekBar
        style="@style/progress_horizontal_my"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />


</LinearLayout>


这样的布局会出现底部剪头不显示的问题,如下即可解决:


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:orientation="vertical">
        <com.jayce.uidefine.RangeSeekBar
            style="@style/progress_horizontal_my"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />
    </LinearLayout>


</LinearLayout>




你可能感兴趣的:(Android RangeSeekBarView 选定范围值的控件)