android自定义View——等级滑动条

先看效果,用豌豆荚演示功能做的Gif,比较卡顿
android自定义View——等级滑动条_第1张图片

思路:
首先绘制直线,然后等分直线绘制点;
绘制点的时候把X值存到集合中。
然后绘制背景图片,以及图片上的数字。
点击事件down的时候,换小图片为大图片。move的时候跟随手指移动。
up的时候根据此时的X计算最近的集合中的点,然后自动吸附回去。

1,自定义属性


<resources>
     <declare-styleable name="BeautySeekBarView">  
        <attr name="valueCountent" format="integer"/>  
         <attr name="padding" format="dimension"/>     
        <attr name="pointColor" format="color"/>  
        <attr name="lineColor" format="color"/>
        <attr name="smallPic" format="reference"/>  
        <attr name="bigPic" format="reference"/>    
    declare-styleable>  
resources>

然后获取属性:

  /** 
         * 获得我们所定义的自定义样式属性 
         */  
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.BeautySeekBarView, defStyleAttr, 0);
        //等级数量即点的个数
        valueCountent=a.getInteger(R.styleable.BeautySeekBarView_valueCountent, 5);
        //点的颜色
        pointColor = a.getColor(R.styleable.BeautySeekBarView_pointColor, Color.WHITE);  
        //线的颜色
        lineColor = a.getColor(R.styleable.BeautySeekBarView_lineColor, Color.WHITE);
        //小图片
        smallPic=a.getResourceId(R.styleable.BeautySeekBarView_smallPic, R.drawable.ic_launcher);
        //滑动过程中的大图片
        bigPic=a.getResourceId(R.styleable.BeautySeekBarView_bigPic, R.drawable.ic_launcher);    
        //控件的内边距
        viewPadding=a.getDimensionPixelSize(R.styleable.BeautySeekBarView_padding, (int) TypedValue.applyDimension(  
                        TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));

        a.recycle();        

2.绘制

@Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);

        float PointX = 0;
        float PointY=getHeight()/2;     
        canvas.drawLine(0+getPaddingLeft(),PointY, getWidth()-getPaddingRight(), PointY, linePaint); //绘制直线

        int averageLength =(getWidth()-getPaddingLeft()-getPaddingRight())/(valueCountent-1);
        for(int i=0;i//绘制点

            if(pointList!=null && pointList.size()//把每个点都放入集合中;
            }           
        }
        sePoolTH.release();
        canvas.drawBitmap(mBitmap, bitmapPointX-bitmapWidth/2, PointY-bitmapHeight/2, null);//绘制拖动的图片 
        canvas.drawText(""+index, bitmapPointX, (getHeight() - fontMetrics.ascent - fontMetrics.descent) / 2, textPaint); //绘制文字
    }

全部代码如下

import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.Semaphore;


import android.R.integer;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

public class BeautySeekBarView extends View {

    private Semaphore sePoolTH=new Semaphore(0);//信号量,解决并发问题

    private int valueCountent;//等级点的数量
    private int pointColor;
    private int lineColor;
    private Bitmap mBitmap;
    private int bitmapWidth;
    private int bitmapHeight;
    private float bitmapPointX;
    private ArrayList pointList;//储存画出的点的point值
    private HashMap mHashMap;////把差值和listX当做键值对保存起来,便于后期找出
    private int index=1;//索引
    private float mListX;//移动后最小的点
    private int smallPic;
    private int bigPic;
    private int viewPadding;  

    private Paint pointPaint;
    private Paint linePaint;
    private Paint textPaint;
    private FontMetricsInt fontMetrics;


    public BeautySeekBarView(Context context) {
        this(context,null);     
    }
    public BeautySeekBarView(Context context, AttributeSet attrs) {
        this(context, attrs,0);     
    }
    public BeautySeekBarView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);                
          /** 
         * 获得我们所定义的自定义样式属性 
         */  
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.BeautySeekBarView, defStyleAttr, 0);
        //等级数量即点的个数
        valueCountent=a.getInteger(R.styleable.BeautySeekBarView_valueCountent, 5);
        //点的颜色
        pointColor = a.getColor(R.styleable.BeautySeekBarView_pointColor, Color.WHITE);  
        //线的颜色
        lineColor = a.getColor(R.styleable.BeautySeekBarView_lineColor, Color.WHITE);
        //小图片
        smallPic=a.getResourceId(R.styleable.BeautySeekBarView_smallPic, R.drawable.ic_launcher);
        //滑动过程中的大图片
        bigPic=a.getResourceId(R.styleable.BeautySeekBarView_bigPic, R.drawable.ic_launcher);    
        //控件的内边距
        viewPadding=a.getDimensionPixelSize(R.styleable.BeautySeekBarView_padding, (int) TypedValue.applyDimension(  
                        TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));

        a.recycle();        

        initData();//初始化数据  
        initPaint();//初始化画笔    
    }
    public void initData() {
//      valueCountent=7;
//      pointColor=Color.WHITE;
//      lineColor=Color.WHITE;          
//      setBackgroundColor(Color.BLACK);        
        setPadding(viewPadding, viewPadding, viewPadding, viewPadding);
        bitmapPointX=getPaddingLeft();
        mBitmap=BitmapFactory.decodeResource(getResources(), smallPic);
        bitmapWidth=mBitmap.getWidth();
        bitmapHeight=mBitmap.getHeight();
        pointList=new ArrayList();
        mHashMap=new HashMap();
    }
    public void initPaint() {
        pointPaint=new Paint();
        pointPaint.setColor(pointColor);
        pointPaint.setStyle(Paint.Style.FILL);
        pointPaint.setStrokeWidth(10);
        pointPaint.setStrokeJoin(Paint.Join.ROUND);
        pointPaint.setStrokeCap(Paint.Cap.ROUND);
        pointPaint.setAntiAlias(true);  

        linePaint=new Paint();
        linePaint.setColor(lineColor);
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setStrokeWidth(4);
        linePaint.setAntiAlias(true);  

        textPaint=new Paint();
        textPaint.setStrokeWidth(3);    
        textPaint.setTextSize(24);    
        textPaint.setColor(Color.WHITE);  
        textPaint.setTextAlign(Paint.Align.CENTER);       
        fontMetrics = textPaint.getFontMetricsInt();  
        textPaint.setAntiAlias(true);  

    }

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // TODO Auto-generated method stub
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);

        float PointX = 0;
        float PointY=getHeight()/2;     
        canvas.drawLine(0+getPaddingLeft(),PointY, getWidth()-getPaddingRight(), PointY, linePaint); //绘制直线

        int averageLength =(getWidth()-getPaddingLeft()-getPaddingRight())/(valueCountent-1);
        for(int i=0;i//绘制点

            if(pointList!=null && pointList.size()//把每个点都放入集合中;
            }           
        }
        sePoolTH.release();
        canvas.drawBitmap(mBitmap, bitmapPointX-bitmapWidth/2, PointY-bitmapHeight/2, null);//绘制拖动的图片 
        canvas.drawText(""+index, bitmapPointX, (getHeight() - fontMetrics.ascent - fontMetrics.descent) / 2, textPaint); //绘制文字
    }

    long  startTime = 0;
    @Override
    public boolean onTouchEvent(MotionEvent event) {             
                //获取手指的操作--》按下、移动、松开
                int action = event.getAction();
                switch (action) {
                case MotionEvent.ACTION_DOWN:   
                    startTime=System.currentTimeMillis();
                    mBitmap=BitmapFactory.decodeResource(getResources(), bigPic);
                    bitmapWidth=mBitmap.getWidth();
                    bitmapHeight=mBitmap.getHeight();
                    textPaint.setTextSize(30); 
                    //invalidate();
                    break;              
                case MotionEvent.ACTION_MOVE:               
                    long endTimeMove=System.currentTimeMillis();                
                    if(endTimeMove-startTime>100){//如果按下,抬起时间过大才认为是拖动,要执行动画。
                     bitmapPointX=event.getX();
                     updateIndex(bitmapPointX);
                     invalidate();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    long  endTime=System.currentTimeMillis();
                    bitmapPointX=event.getX();
                    mBitmap=BitmapFactory.decodeResource(getResources(),smallPic);
                    bitmapWidth=mBitmap.getWidth();
                    bitmapHeight=mBitmap.getHeight();
                    textPaint.setTextSize(24);                          
                    if(endTime-startTime>200){//如果按下,抬起时间过大才认为是拖动,要执行动画。
                    updateBitmapUI(bitmapPointX);
                    }else{                      
                        bitmapPointX=updateIndex(bitmapPointX);
                        invalidate();
                    }
                    startTime = 0;
                    break;
                }
                return true;
    }
    //更新索引
    public float updateIndex(float pointX){
        float lastValue=100000;
        float currentValue=0;
        float minValue=0;
         for(float listX:pointList){
              currentValue= Math.abs(pointX-listX);
              mHashMap.put(currentValue, listX);//把差值和listX当做键值对保存起来,便于后期找出
              minValue=Math.min(lastValue,currentValue);
              lastValue=minValue;
            }           
        if(mHashMap.containsKey(minValue)){
            mListX=mHashMap.get(minValue);
        }else{
           Log.e("BeautySeekBarView", "updateBitmapUI--->mHashMap.containsKey(minValue) is null");
           return -1;
        } 
        if(pointList.contains(mListX)){
        index=pointList.indexOf(mListX)+1;
        if(mListener!=null){
            mListener.getIndex(index);
        }
        }else{
            Log.e("BeautySeekBarView", "updateBitmapUI--->pointList.contains(mListX) is null");
               return -1;
        }
        return mListX;
    }

    //当手指抬起后更新Bitmap的位置
    private void updateBitmapUI(float PointX2) {
        mListX=updateIndex(PointX2);
        //执行动画      
        ValueAnimator anim = ValueAnimator.ofFloat(PointX2, mListX);
        anim.setDuration(50);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                bitmapPointX =(Float) animation.getAnimatedValue();
                invalidate();
            }
        });
        anim.start();
    }

    //设置等级点的数量
    public void pointValueCountent(int countent){
        if(countent<2){
            valueCountent=2;
        }else{
            valueCountent=countent;
        }
        invalidate();
    }

    //设置默认位置
    public void setPointLocation(final int location){
        new Thread(new Runnable() {

            @Override
            public void run() {             
                 try {
                        sePoolTH.acquire();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }       
                    if(location>0&&pointList!=null&& !pointList.isEmpty()){
                        bitmapPointX=pointList.get(location-1);
                        postInvalidate();
                    }

            }
        }).start();

    }

    //提供接口回调,获取索引
    private indexListener mListener=null;
    public interface indexListener{
        void getIndex(int index);
    }
    public void setIndexListener(indexListener listener){
        mListener=listener;
    }

}

外部调用:
XML:

 <com.example.hello.BeautySeekBarView 
        android:id="@+id/myView"
        android:layout_centerVertical="true"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        ws:padding="20dp"         
        ws:valueCountent="6"      
        ws:pointColor="#FFFFFF"
        ws:lineColor="#FFFFFF"
        ws:smallPic="@drawable/beauty_seekbar_point"
        ws:bigPic="@drawable/beauty_seekbar_point_big"/>

Java:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);    
        setContentView(R.layout.activity_main);

      initView(); 

      beautySeekBarView.setPointLocation(2) ;
       //

    }

    private void initView() {
    mTextView=(TextView) findViewById(R.id.tv);
    beautySeekBarView=(BeautySeekBarView) findViewById(R.id.myView);
    beautySeekBarView.setIndexListener(new indexListener() {    
        @Override
        public void getIndex(int index) {
            mTextView.setText("index="+index);  
        }
    });
    }

你可能感兴趣的:(Android自定义View)