比好看的一些自定义SeekBar

来源:互联网 发布:linux集成开发环境 编辑:程序博客网 时间:2024/04/30 22:36

看到了一个App自定义的SeekBar很有趣,尝试着自己做一个。

不废话,先上图,看是否是你期望的:


增加了背景图片的自定义,增加了Thumb的自定义。当然还有动画效果。会动画滑动到附近的点。具体代码稍后奉上...

啊。。。乱七八糟事儿太多,这几天都没时间整理

这个demo的点可以自定义数量,并增加回调。我就不写原理了...直接把代码传上去...有时间再写...


首先需要画出seekbar的背景drawable:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.zkbc.tougu.demo;  
  2.   
  3. import android.graphics.Canvas;  
  4. import android.graphics.Color;  
  5. import android.graphics.ColorFilter;  
  6. import android.graphics.LinearGradient;  
  7. import android.graphics.Paint;  
  8. import android.graphics.Rect;  
  9. import android.graphics.RectF;  
  10. import android.graphics.Shader;  
  11. import android.graphics.drawable.Drawable;  
  12.   
  13. /** 
  14.  * 自定义seekBar背景图 
  15.  * Created by Rock Lee on 2016/6/21. 
  16.  */  
  17. public class MySeekBarDrawable extends Drawable {  
  18.   
  19.     int pointCount;  
  20.     int startColor;  
  21.     int centerColor;  
  22.     int endColor;  
  23.   
  24.     private Paint paint;//画笔(背景)  
  25.     LinearGradient shader;  
  26.   
  27.     private Paint paintCircle;//画笔-外圆  
  28.     private Paint paintCircleCenter;//画笔-内圆  
  29.     RectF rectF;//矩形上下左右的坐标  
  30.     int colors[] = new int[3];//三个颜色渐变(shader)  
  31.     float positions[] = new float[3];//渐变色的三个点(shader)  
  32.   
  33.     public MySeekBarDrawable(int pointCount, int startColor, int centerColor, int endColor) {  
  34.         this.pointCount = pointCount * 2;//增加两点之间的中线  
  35.         this.startColor = startColor;  
  36.         this.centerColor = centerColor;  
  37.         this.endColor = endColor;  
  38.   
  39.         paint = new Paint();  
  40.         paintCircle = new Paint();  
  41.         paintCircleCenter = new Paint();  
  42.         rectF = new RectF();  
  43.     }  
  44.   
  45.     @Override  
  46.     public void draw(Canvas canvas) {  
  47.         final Rect bounds = getBounds();  
  48.         // 第1个点  
  49.         colors[0] = startColor;  
  50.         positions[0] = 0;  
  51.   
  52.         // 第2个点  
  53.         colors[1] = centerColor;  
  54.         positions[1] = 0.5f;  
  55.   
  56.         // 第3个点  
  57.         colors[2] = endColor;  
  58.         positions[2] = 1;  
  59.   
  60.         //是否有中间色  
  61.         if (centerColor == 0) {  
  62.             shader = new LinearGradient(0f, 0f, bounds.width(), bounds.height(), startColor, endColor, Shader.TileMode.MIRROR);  
  63.         } else {  
  64.             shader = new LinearGradient(0f, 0f, bounds.width(), bounds.height(), colors, positions, Shader.TileMode.MIRROR);  
  65.         }  
  66.         paint.setShader(shader);  
  67.         paint.setStrokeCap(Paint.Cap.ROUND);// 圆角  
  68.         paint.setAntiAlias(true); // 消除锯齿  
  69.   
  70.         paintCircle.setShader(shader);  
  71. //        paintCircle.setStyle(Paint.Style.STROKE); // 设置空心  
  72. //        paintCircle.setStrokeWidth(bounds.height()/2); // 设置笔画的宽度  
  73.         paintCircle.setAntiAlias(true); // 消除锯齿  
  74.   
  75.         paintCircleCenter.setAntiAlias(true); // 消除锯齿  
  76.         paintCircleCenter.setColor(Color.WHITE);  
  77.   
  78.         float lineHeight = bounds.height()/4.0f;  
  79.   
  80.         rectF.set(0, bounds.centerY() - lineHeight, bounds.width(), bounds.centerY() + lineHeight);  
  81.         //绘制圆角矩形  
  82.         canvas.drawRoundRect(rectF, lineHeight, lineHeight, paint);  
  83.   
  84.         float section = (float) bounds.width() / pointCount;  
  85.   
  86.         for (int i = 1; i < pointCount; i++) {  
  87.             paint.setShader(null);  
  88.             paint.setColor(Color.WHITE);  
  89. //            paint.setStrokeWidth(1);  
  90.   
  91.             float cx = section * i;//X轴圆心坐标  
  92.   
  93.             if (i % 2 == 0) {  
  94.                 canvas.drawLine(cx, bounds.centerY() - lineHeight, cx, bounds.centerY() + lineHeight, paint);  
  95.             } else {  
  96.                 canvas.drawCircle(cx, bounds.centerY(), lineHeight*2, paintCircle);  
  97.                 canvas.drawCircle(cx, bounds.centerY(), lineHeight, paintCircleCenter);  
  98.             }  
  99.         }  
  100.     }  
  101.   
  102.     @Override  
  103.     public void setAlpha(int alpha) {  
  104.         paint.setAlpha(alpha);  
  105.     }  
  106.   
  107.     @Override  
  108.     public void setColorFilter(ColorFilter colorFilter) {  
  109.         paint.setColorFilter(colorFilter);  
  110.     }  
  111.   
  112.     @Override  
  113.     public int getOpacity() {  
  114.         return 1 - paint.getAlpha();  
  115.     }  
  116.   
  117.     /** 
  118.      * MySeekBarDrawable Builder 
  119.      */  
  120.     public static class Builder {  
  121.   
  122.         /** 
  123.          * 分割段数 
  124.          */  
  125.         int pointCount;  
  126.   
  127.         /** 
  128.          * 起始颜色 
  129.          */  
  130.         int startColor;  
  131.   
  132.         /** 
  133.          * 中间色 
  134.          */  
  135.         int centerColor;  
  136.   
  137.         /** 
  138.          * 结束颜色 
  139.          */  
  140.         int endColor;  
  141.   
  142.         /** 
  143.          * Sets the seekBar point count. 
  144.          * 
  145.          * @returns This Builder 
  146.          */  
  147.         public Builder setPointCount(int pointCount) {  
  148.             this.pointCount = pointCount;  
  149.             return this;  
  150.         }  
  151.   
  152.         /** 
  153.          * Sets the seekBar start color. 
  154.          * 
  155.          * @param startColor start color in #AARRGGBB format. 
  156.          * @returns This Builder 
  157.          */  
  158.         public Builder setStartColor(int startColor) {  
  159.             this.startColor = startColor;  
  160.             return this;  
  161.         }  
  162.   
  163.         /** 
  164.          * Sets the seekBar center color. 
  165.          * 
  166.          * @param centerColor center color in #AARRGGBB format. 
  167.          * @returns This Builder 
  168.          */  
  169.         public Builder setCenterColor(int centerColor) {  
  170.             this.centerColor = centerColor;  
  171.             return this;  
  172.         }  
  173.   
  174.         /** 
  175.          * Sets the seekBar end color. 
  176.          * 
  177.          * @param endColor end color in #AARRGGBB format. 
  178.          * @returns This Builder 
  179.          */  
  180.         public Builder setEndColor(int endColor) {  
  181.             this.endColor = endColor;  
  182.             return this;  
  183.         }  
  184.   
  185.         /** 
  186.          * Creates a new MySeekBarDrawable with the requested parameters 
  187.          * 
  188.          * @return New MySeekBarDrawableInstance 
  189.          */  
  190.         public MySeekBarDrawable create() {  
  191.             return new MySeekBarDrawable(pointCount, startColor, centerColor, endColor);  
  192.         }  
  193.     }  
  194. }  

第二步:自定义seekbar,并将我们的自定义drawable附上:


[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.zkbc.tougu.demo;  
  2.   
  3. import android.animation.Animator;  
  4. import android.animation.AnimatorSet;  
  5. import android.animation.ObjectAnimator;  
  6. import android.content.Context;  
  7. import android.content.res.TypedArray;  
  8. import android.graphics.Bitmap;  
  9. import android.graphics.Canvas;  
  10. import android.graphics.Color;  
  11. import android.graphics.drawable.BitmapDrawable;  
  12. import android.graphics.drawable.Drawable;  
  13. import android.util.AttributeSet;  
  14. import android.view.LayoutInflater;  
  15. import android.view.View;  
  16. import android.view.ViewGroup;  
  17. import android.view.animation.AccelerateDecelerateInterpolator;  
  18. import android.widget.LinearLayout;  
  19. import android.widget.PopupWindow;  
  20. import android.widget.SeekBar;  
  21. import android.widget.TextView;  
  22.   
  23. import com.zkbc.tougu.R;  
  24.   
  25. /** 
  26.  * 自定义seekBar 
  27.  * Created by Rock Lee on 2016/6/21. 
  28.  */  
  29. public class MyNiceSeekBar extends SeekBar implements SeekBar.OnSeekBarChangeListener {  
  30.   
  31.     private int pointCount;  
  32.   
  33.     private int startColor;  
  34.   
  35.     private int centerColor;  
  36.   
  37.     private int endColor;  
  38.   
  39.     public final int oneLength = 100;//每个隔断的刻度  
  40.     int risk;  
  41.   
  42.     TextView centerText;  
  43.     Drawable thumbDrawable;  
  44.     View thumb;  
  45.   
  46.     MySeekBarDrawable drawable;  
  47.   
  48.     SeekBarInterface barInterface;//参数回调  
  49.   
  50.     SeekBarOnDrawListener onDrawListener;//seekBar绘画监听  
  51.   
  52.     private boolean mPopupStyle;//是否显示pop  
  53.     private boolean mThumbStyle;  
  54.     private int xOffset;  
  55.     private PopupWindow mPopup;  
  56.     private TextView mPopupTextView;  
  57.     private int mYLocationOffset;  
  58.   
  59.     public MyNiceSeekBar(Context context) {  
  60.         this(context, null);  
  61.     }  
  62.   
  63.     public MyNiceSeekBar(Context context, AttributeSet attrs) {  
  64.         this(context, attrs, 0);  
  65.     }  
  66.   
  67.     public MyNiceSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {  
  68.         super(context, attrs, defStyleAttr);  
  69.         init(context, attrs);  
  70.   
  71.     }  
  72.   
  73.     private void init(Context context, AttributeSet attrs) {  
  74.   
  75.         TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.MySeekBar);  
  76.   
  77.         pointCount = mTypedArray.getInteger(R.styleable.MySeekBar_pointCount, 5);  
  78.         startColor = mTypedArray.getColor(R.styleable.MySeekBar_startColor, Color.GREEN);  
  79.         centerColor = mTypedArray.getColor(R.styleable.MySeekBar_centerColor, 0);  
  80.         endColor = mTypedArray.getColor(R.styleable.MySeekBar_endColor, Color.RED);  
  81.         mPopupStyle = mTypedArray.getBoolean(R.styleable.MySeekBar_popupStyle, false);  
  82.         mThumbStyle = mTypedArray.getBoolean(R.styleable.MySeekBar_popupStyle, false);  
  83.         xOffset = (int) mTypedArray.getDimension(R.styleable.MySeekBar_xOffset, 0);  
  84.         mYLocationOffset = (int) mTypedArray.getDimension(R.styleable.MySeekBar_yOffset, 0);  
  85.   
  86.         mTypedArray.recycle();  
  87.   
  88.         setMax(pointCount * 2 * oneLength);  
  89.   
  90.         setProgress(3 * oneLength);  
  91.         setOnSeekBarChangeListener(this);  
  92.   
  93.         drawable = new MySeekBarDrawable.Builder()  
  94.                 .setPointCount(pointCount)  
  95.                 .setStartColor(startColor)  
  96.                 .setCenterColor(centerColor)  
  97.                 .setEndColor(endColor).create();  
  98.         setProgressDrawable(drawable);  
  99.         initThumb((getProgress() / (2 * oneLength) + 1) + "");  
  100.         initHintPopup();  
  101.     }  
  102.   
  103.     public void initThumb(String risk) {  
  104.         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  105.         thumb = inflater.inflate(R.layout.seekbar_thumb, null);  
  106.         centerText = (TextView) thumb.findViewById(R.id.text1);  
  107.         if (mThumbStyle) {  
  108.             centerText.setText(risk);  
  109.         }  
  110.         thumbDrawable = convertViewToDrawable(thumb);  
  111.         setThumb(thumbDrawable);  
  112.     }  
  113.   
  114.     public static Drawable convertViewToDrawable(View view) {  
  115.         view.measure(  
  116.                 View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),  
  117.                 View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));  
  118.         view.layout(00, view.getMeasuredHeight(), view.getMeasuredHeight());  
  119.         view.setDrawingCacheEnabled(true);  
  120.         Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(true));  
  121.         Drawable drawable = new BitmapDrawable(null, bitmap);  
  122.         view.destroyDrawingCache();  
  123.         view.setDrawingCacheEnabled(false);  
  124.         return drawable;  
  125.     }  
  126.   
  127.     @Override  
  128.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  129.         super.onSizeChanged(w, h, oldw, oldh);  
  130.     }  
  131.   
  132.     @Override  
  133.     protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  134.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  135.         setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());  
  136.     }  
  137.   
  138.     @Override  
  139.     protected synchronized void onDraw(Canvas canvas) {  
  140.         super.onDraw(canvas);  
  141.         if (onDrawListener != null) {  
  142.             onDrawListener.onDrawListener();  
  143.         }  
  144.     }  
  145.   
  146.     @Override  
  147.     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {  
  148.         //进度改变时调用  
  149.         risk = getTargetProgress(seekBar) / (2 * oneLength) + 1;  
  150.         String popupText;  
  151.         if (barInterface != null) {  
  152.             int targetProgress = getTargetProgress(seekBar);  
  153.             popupText = barInterface.progressChangeCallBack(this, getProgress(), targetProgress);  
  154.             mPopupTextView.setText(popupText != null ? popupText : String.valueOf(targetProgress));  
  155.         }  
  156.         if (mPopupStyle && mPopup != null) {  
  157.             showPopup();  
  158.             mPopup.update(this, (int) getXPosition(getProgress(), mPopup.getContentView()), -(this.getHeight() + mPopup.getContentView().getMeasuredHeight() + mYLocationOffset), -1, -1);  
  159.         } else {  
  160.             hidePopup();  
  161.         }  
  162.     }  
  163.   
  164.     @Override  
  165.     public void onStartTrackingTouch(SeekBar seekBar) {  
  166.         //进度条开始拖动的时候调用  
  167.         showPopup();  
  168.         centerText.setText("");  
  169.         thumbDrawable = convertViewToDrawable(thumb);  
  170.         setThumb(thumbDrawable);  
  171.     }  
  172.   
  173.     @Override  
  174.     public void onStopTrackingTouch(SeekBar seekBar) {  
  175.         //进度条停止拖动的时候调用  
  176.         int targetProgress = getTargetProgress(seekBar);  
  177.         dodo(seekBar.getProgress(), targetProgress);  
  178.         if (mThumbStyle) {  
  179.             centerText.setText(risk + "");  
  180.         }  
  181.         thumbDrawable = convertViewToDrawable(thumb);  
  182.         setThumb(thumbDrawable);  
  183.     }  
  184.   
  185.     /** 
  186.      * 赋值+执行动画 
  187.      * 
  188.      * @param progressText   当前滑动的点 
  189.      * @param targetProgress 自动滑动到目标点 
  190.      */  
  191.     public void dodo(int progressText, int targetProgress) {  
  192.         AnimatorSet animation = new AnimatorSet();  
  193.   
  194.         ObjectAnimator progressAnimation = ObjectAnimator.ofInt(this"progress",  
  195.                 progressText, targetProgress);  
  196.         progressAnimation.setDuration(300);  
  197.         progressAnimation.setInterpolator(new AccelerateDecelerateInterpolator());  
  198.         //增加动画监听  
  199.         progressAnimation.addListener(new Animator.AnimatorListener() {  
  200.             @Override  
  201.             public void onAnimationStart(Animator animation) {  
  202.   
  203.             }  
  204.   
  205.             @Override  
  206.             public void onAnimationEnd(Animator animation) {  
  207.                 hidePopup();  
  208.             }  
  209.   
  210.             @Override  
  211.             public void onAnimationCancel(Animator animation) {  
  212.                 hidePopup();  
  213.             }  
  214.   
  215.             @Override  
  216.             public void onAnimationRepeat(Animator animation) {  
  217.   
  218.             }  
  219.         });  
  220.         animation.playTogether(progressAnimation);  
  221.         animation.start();  
  222.     }  
  223.   
  224.     /** 
  225.      * 选中回调 
  226.      * 
  227.      * @param barInterface 回调监听 
  228.      */  
  229.     public void setSeekBarCallBack(SeekBarInterface barInterface) {  
  230.         this.barInterface = barInterface;  
  231.     }  
  232.   
  233.     /** 
  234.      * 绘画监听接口 
  235.      * 
  236.      * @param onDrawListener 绘画监听实现接口 
  237.      */  
  238.     public void setOnDrawListener(SeekBarOnDrawListener onDrawListener) {  
  239.         this.onDrawListener = onDrawListener;  
  240.     }  
  241.   
  242.     /** 
  243.      * 是否显示pop 
  244.      * @param style 是否显示pop 
  245.      */  
  246.     public void setPopupStyle(boolean style) {  
  247.         mPopupStyle = style;  
  248.     }  
  249.   
  250.     private void initHintPopup() {  
  251.         String popupText = null;  
  252.   
  253.         if (barInterface != null) {  
  254.             int targetProgress = getTargetProgress(this);  
  255.             popupText = barInterface.progressChangeCallBack(this, getProgress(), targetProgress);  
  256.         }  
  257.   
  258.         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  259.         final View undoView = inflater.inflate(R.layout.popup, null);  
  260.         mPopupTextView = (TextView) undoView.findViewById(R.id.text);  
  261.         mPopupTextView.setText(popupText != null ? popupText : String.valueOf(getProgress()));  
  262.   
  263.         mPopup = new PopupWindow(undoView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, false);  
  264.         mPopup.getContentView().measure(00);//获取测量后的popWindow高度  
  265.   
  266.         mPopup.setAnimationStyle(R.style.fade_animation);  
  267.   
  268.     }  
  269.   
  270.     private void showPopup() {  
  271.         if (mPopupStyle) {  
  272.             mPopup.showAsDropDown(this, (int) getXPosition(getProgress(), mPopup.getContentView()), -(this.getHeight() + mPopup.getContentView().getMeasuredHeight() + mYLocationOffset));  
  273.         }  
  274.     }  
  275.   
  276.     private void hidePopup() {  
  277.         if (mPopup != null && mPopup.isShowing()) {  
  278.             mPopup.dismiss();  
  279.         }  
  280.     }  
  281.   
  282.     /** 
  283.      * 获取X坐标 
  284.      * 
  285.      * @param progress 进度 
  286.      * @param v        在seekBar上显示的View 
  287.      * @return X 
  288.      */  
  289.     private float getXPosition(int progress, View v) {  
  290.         //seekBar总宽度包含ThumbOffset两边  
  291.         float val = (((float) progress * ((float) getWidth())) / (float) getMax());  
  292.         int textWidth = v.getMeasuredWidth();  
  293.         float textCenter = (textWidth / 2.0f) + xOffset;  
  294.         return val - textCenter;  
  295.     }  
  296.   
  297.     /** 
  298.      * 获取目标进度 
  299.      * 
  300.      * @return 返回目标进度 
  301.      */  
  302.     private int getTargetProgress(SeekBar seekBar) {  
  303.         int targetProgress;//进度参数回调默认值  
  304.   
  305.         int proNow = seekBar.getProgress();//当前点  
  306.         int yu = proNow % oneLength;//取余数  
  307.         if ((proNow / oneLength) % 2 == 0) {  
  308.             //是否为满进度,满进度回退一格  
  309.             targetProgress = proNow == getMax() ? proNow - oneLength : proNow + oneLength - yu;  
  310.         } else {  
  311.             targetProgress = proNow - yu;  
  312.         }  
  313.         return targetProgress;  
  314.     }  
  315.   
  316.     /** 
  317.      * 设置推荐坐标 
  318.      * 
  319.      * @param recommendPosition 显示在第几个点,从0开始 
  320.      * @param ll_recommend 
  321.      */  
  322.     public void setRecommendPosition(int recommendPosition, View ll_recommend) {  
  323.         int progress = oneLength + recommendPosition * 2 * oneLength;  
  324.         float x = getXPosition(progress, ll_recommend);  
  325.         LinearLayout.LayoutParams pa = (LinearLayout.LayoutParams) ll_recommend.getLayoutParams();  
  326.         pa.setMargins((int) x, 000);  
  327.         ll_recommend.setLayoutParams(pa);  
  328.     }  
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public int getRisk() {  
  2.     return risk;  
  3. }  
  4.   
  5. public void setRisk(int risk) {  
  6.     this.risk = risk;  
  7. }  
  8.   
  9. /** 
  10.  * 是否显示Thumb数字 
  11.  * @param mThumbStyle 
  12.  */  
  13. public void setThumbStyle(boolean mThumbStyle) {  
  14.     this.mThumbStyle = mThumbStyle;  
  15. }  

使用方式:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private void initSeekbar() {  
  2.         recommend = 3;  
  3.         mSeekBar1.initThumb((mSeekBar1.getProgress() / (2 * mSeekBar1.oneLength)) + "");  
  4.         mSeekBar1.setSeekBarCallBack(new SeekBarInterface() {  
  5.             @Override  
  6.             public String progressChangeCallBack(MyNiceSeekBar myNiceSeekBar, int progress, int targetProgress) {  
  7.                 risk = myNiceSeekBar.getRisk();  
  8.                 myNiceSeekBar.setRisk(risk);  
  9.                   
  10.                 //返回Pop上需要显示的字符串  
  11.                 return "节点" + risk;  
  12.             }  
  13.         });  
  14.         mSeekBar1.setOnDrawListener(new SeekBarOnDrawListener() {  
  15.             @Override  
  16.             public void onDrawListener() {  
  17.                 mSeekBar1.setRecommendPosition(recommend, ll_recommend);  
  18.             }  
  19.         });  
  20.     }  
0 0