Android自定义View实现等级滑动条的实例

Android自定义View实现等级滑动条的实例

实现效果图:

思路:

首先绘制直线,然后等分直线绘制点;

绘制点的时候把X值存到集合中。

然后绘制背景图片,以及图片上的数字。

点击事件down的时候,换小图片为大图片。move的时候跟随手指移动。

up的时候根据此时的X计算最近的集合中的点,然后自动吸附回去。

1,自定义属性

<?xml version="1.0" encoding="utf-8"?> <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<valueCountent;i++){ PointX=i*averageLength+getPaddingLeft(); canvas.drawPoint(PointX, PointY, pointPaint);//绘制点 if(pointList!=null && pointList.size()<valueCountent){ pointList.add(PointX);//把每个点都放入集合中; } } 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<Float> pointList;//储存画出的点的point值 private HashMap<Float, Float> 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<Float>(); mHashMap=new HashMap<Float, Float>(); } 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<valueCountent;i++){ PointX=i*averageLength+getPaddingLeft(); canvas.drawPoint(PointX, PointY, pointPaint);//绘制点 if(pointList!=null && pointList.size()<valueCountent){ pointList.add(PointX);//把每个点都放入集合中; } } 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); } }); }

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

时间: 2017-11-28

Android自定义View实现等级滑动条的实例的相关文章

Android自定义View实现左右滑动选择出生年份_Android

自定义view的第三篇,模仿的是微博运动界面的个人出生日期设置view,先看看我的效果图: 支持设置初始年份,左右滑动选择出生年份,对应的TextView的值也会改变.这个动画效果弄了好久,感觉还是比较生硬,与微博那个还是有点区别.大家有改进的方案,欢迎一起交流. 自定义View四部曲,这里依旧是这个套路,看看怎么实现的. 1.自定义view的属性: 在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性以及声明我们的整个样式. <?xml version="1.

Android自定义View实现左右滑动选择出生年份

自定义view的第三篇,模仿的是微博运动界面的个人出生日期设置view,先看看我的效果图: 支持设置初始年份,左右滑动选择出生年份,对应的TextView的值也会改变.这个动画效果弄了好久,感觉还是比较生硬,与微博那个还是有点区别.大家有改进的方案,欢迎一起交流. 自定义View四部曲,这里依旧是这个套路,看看怎么实现的. 1.自定义view的属性: 在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性以及声明我们的整个样式. <?xml version="1.

Android自定义View之圆形进度条总结

最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View .在此对项目开发思路做个小结,欢迎大家 Star 和 Fork. 该项目总共实现了三种圆形进度条效果 CircleProgress:圆形进度条,可以实现仿 QQ 健康计步器的效果,支持配置进度条背景色.宽度.起始角度,支持进度条渐变 DialProgress:类似 CircleProgress,但是支持刻度 WaveProgress:实现了水波纹效果的圆形进度条,不支持渐变和起始角度配置,如需此功能可参考 CircleP

Android自定义View之圆形进度条式按钮_Android

介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

Android自定义View之圆形进度条式按钮

介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

Android自定义View实现BMI指数条_Android

最近项目需要,需要做一个BMI指数的指示条,先上效果图: BMI指数从18到35,然后上面指示条的颜色会随着偏移量的变化而改变,数字显示当前的BMI指数,下面的BMI标准也是根据不同数值的范围来判断的.考虑到这个view的特殊性,最后采用的是自定义的view来完成的. 1.页面布局: <LinearLayout android:layout_width="fill_parent" android:layout_height="100dp" android:la

Android自定义view之圆形进度条

本节介绍自定义view-圆形进度条 思路: 根据前面介绍的自定义view内容可拓展得之: 1:新建类继承自View 2:添加自定义view属性 3:重写onDraw(Canvas canvas) 4:实现功能 下面上代码 1.自定义view代码: public class CustomView extends View { //背景圆环颜色 private int circleColor; //进度条颜色&字体颜色(为了美观,所以设计字体颜色和进度条颜色值一致) private int seco

Android自定义View制作动态炫酷按钮实例解析_Android

普通按钮也就那么几种样式,看着都审美疲劳,先放效果图:   你会不会以为这个按钮是集结了很多动画的产物,我告诉你,并没有.所有的实现都是基于自定义View,采用最底层的onDraw一点一点的画出来的.没有采用一丁点的动画.虽然演示时间很短,但是要完成这么多变化,还是挺吃力. 首先讲解用法:  public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceStat

Android自定义View制作动态炫酷按钮实例解析

普通按钮也就那么几种样式,看着都审美疲劳,先放效果图: 你会不会以为这个按钮是集结了很多动画的产物,我告诉你,并没有.所有的实现都是基于自定义View,采用最底层的onDraw一点一点的画出来的.没有采用一丁点的动画.虽然演示时间很短,但是要完成这么多变化,还是挺吃力. 首先讲解用法: public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState)