自定义漂亮的seekBar,内带popwindow及指示器
来源:互联网 发布:软件测试举例 编辑:程序博客网 时间:2024/04/29 00:21
看到了一个App自定义的SeekBar很有趣,尝试着自己做一个。
不废话,先上图,看是否是你期望的:
增加了背景图片的自定义,增加了Thumb的自定义。当然还有动画效果。会动画滑动到附近的点。具体代码稍后奉上...
啊。。。乱七八糟事儿太多,这几天都没时间整理
这个demo的点可以自定义数量,并增加回调。我就不写原理了...直接把代码传上去...有时间再写...
首先需要画出seekbar的背景drawable:
package com.zkbc.tougu.demo;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.ColorFilter;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.Shader;import android.graphics.drawable.Drawable;/** * 自定义seekBar背景图 * Created by Rock Lee on 2016/6/21. */public class MySeekBarDrawable extends Drawable { int pointCount; int startColor; int centerColor; int endColor; private Paint paint;//画笔(背景) LinearGradient shader; private Paint paintCircle;//画笔-外圆 private Paint paintCircleCenter;//画笔-内圆 RectF rectF;//矩形上下左右的坐标 int colors[] = new int[3];//三个颜色渐变(shader) float positions[] = new float[3];//渐变色的三个点(shader) public MySeekBarDrawable(int pointCount, int startColor, int centerColor, int endColor) { this.pointCount = pointCount * 2;//增加两点之间的中线 this.startColor = startColor; this.centerColor = centerColor; this.endColor = endColor; paint = new Paint(); paintCircle = new Paint(); paintCircleCenter = new Paint(); rectF = new RectF(); } @Override public void draw(Canvas canvas) { final Rect bounds = getBounds(); // 第1个点 colors[0] = startColor; positions[0] = 0; // 第2个点 colors[1] = centerColor; positions[1] = 0.5f; // 第3个点 colors[2] = endColor; positions[2] = 1; //是否有中间色 if (centerColor == 0) { shader = new LinearGradient(0f, 0f, bounds.width(), bounds.height(), startColor, endColor, Shader.TileMode.MIRROR); } else { shader = new LinearGradient(0f, 0f, bounds.width(), bounds.height(), colors, positions, Shader.TileMode.MIRROR); } paint.setShader(shader); paint.setStrokeCap(Paint.Cap.ROUND);// 圆角 paint.setAntiAlias(true); // 消除锯齿 paintCircle.setShader(shader);// paintCircle.setStyle(Paint.Style.STROKE); // 设置空心// paintCircle.setStrokeWidth(bounds.height()/2); // 设置笔画的宽度 paintCircle.setAntiAlias(true); // 消除锯齿 paintCircleCenter.setAntiAlias(true); // 消除锯齿 paintCircleCenter.setColor(Color.WHITE); float lineHeight = bounds.height()/4.0f; rectF.set(0, bounds.centerY() - lineHeight, bounds.width(), bounds.centerY() + lineHeight); //绘制圆角矩形 canvas.drawRoundRect(rectF, lineHeight, lineHeight, paint); float section = (float) bounds.width() / pointCount; for (int i = 1; i < pointCount; i++) { paint.setShader(null); paint.setColor(Color.WHITE);// paint.setStrokeWidth(1); float cx = section * i;//X轴圆心坐标 if (i % 2 == 0) { canvas.drawLine(cx, bounds.centerY() - lineHeight, cx, bounds.centerY() + lineHeight, paint); } else { canvas.drawCircle(cx, bounds.centerY(), lineHeight*2, paintCircle); canvas.drawCircle(cx, bounds.centerY(), lineHeight, paintCircleCenter); } } } @Override public void setAlpha(int alpha) { paint.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter colorFilter) { paint.setColorFilter(colorFilter); } @Override public int getOpacity() { return 1 - paint.getAlpha(); } /** * MySeekBarDrawable Builder */ public static class Builder { /** * 分割段数 */ int pointCount; /** * 起始颜色 */ int startColor; /** * 中间色 */ int centerColor; /** * 结束颜色 */ int endColor; /** * Sets the seekBar point count. * * @returns This Builder */ public Builder setPointCount(int pointCount) { this.pointCount = pointCount; return this; } /** * Sets the seekBar start color. * * @param startColor start color in #AARRGGBB format. * @returns This Builder */ public Builder setStartColor(int startColor) { this.startColor = startColor; return this; } /** * Sets the seekBar center color. * * @param centerColor center color in #AARRGGBB format. * @returns This Builder */ public Builder setCenterColor(int centerColor) { this.centerColor = centerColor; return this; } /** * Sets the seekBar end color. * * @param endColor end color in #AARRGGBB format. * @returns This Builder */ public Builder setEndColor(int endColor) { this.endColor = endColor; return this; } /** * Creates a new MySeekBarDrawable with the requested parameters * * @return New MySeekBarDrawableInstance */ public MySeekBarDrawable create() { return new MySeekBarDrawable(pointCount, startColor, centerColor, endColor); } }}
第二步:自定义seekbar,并将我们的自定义drawable附上:
package com.zkbc.tougu.demo;import android.animation.Animator;import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.animation.AccelerateDecelerateInterpolator;import android.widget.LinearLayout;import android.widget.PopupWindow;import android.widget.SeekBar;import android.widget.TextView;import com.zkbc.tougu.R;/** * 自定义seekBar * Created by Rock Lee on 2016/6/21. */public class MyNiceSeekBar extends SeekBar implements SeekBar.OnSeekBarChangeListener { private int pointCount; private int startColor; private int centerColor; private int endColor; public final int oneLength = 100;//每个隔断的刻度 int risk; TextView centerText; Drawable thumbDrawable; View thumb; MySeekBarDrawable drawable; SeekBarInterface barInterface;//参数回调 SeekBarOnDrawListener onDrawListener;//seekBar绘画监听 private boolean mPopupStyle;//是否显示pop private boolean mThumbStyle; private int xOffset; private PopupWindow mPopup; private TextView mPopupTextView; private int mYLocationOffset; public MyNiceSeekBar(Context context) { this(context, null); } public MyNiceSeekBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyNiceSeekBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.MySeekBar); pointCount = mTypedArray.getInteger(R.styleable.MySeekBar_pointCount, 5); startColor = mTypedArray.getColor(R.styleable.MySeekBar_startColor, Color.GREEN); centerColor = mTypedArray.getColor(R.styleable.MySeekBar_centerColor, 0); endColor = mTypedArray.getColor(R.styleable.MySeekBar_endColor, Color.RED); mPopupStyle = mTypedArray.getBoolean(R.styleable.MySeekBar_popupStyle, false); mThumbStyle = mTypedArray.getBoolean(R.styleable.MySeekBar_popupStyle, false); xOffset = (int) mTypedArray.getDimension(R.styleable.MySeekBar_xOffset, 0); mYLocationOffset = (int) mTypedArray.getDimension(R.styleable.MySeekBar_yOffset, 0); mTypedArray.recycle(); setMax(pointCount * 2 * oneLength); setProgress(3 * oneLength); setOnSeekBarChangeListener(this); drawable = new MySeekBarDrawable.Builder() .setPointCount(pointCount) .setStartColor(startColor) .setCenterColor(centerColor) .setEndColor(endColor).create(); setProgressDrawable(drawable); initThumb((getProgress() / (2 * oneLength) + 1) + ""); initHintPopup(); } public void initThumb(String risk) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); thumb = inflater.inflate(R.layout.seekbar_thumb, null); centerText = (TextView) thumb.findViewById(R.id.text1); if (mThumbStyle) { centerText.setText(risk); } thumbDrawable = convertViewToDrawable(thumb); setThumb(thumbDrawable); } public static Drawable convertViewToDrawable(View view) { view.measure( View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); view.layout(0, 0, view.getMeasuredHeight(), view.getMeasuredHeight()); view.setDrawingCacheEnabled(true); Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(true)); Drawable drawable = new BitmapDrawable(null, bitmap); view.destroyDrawingCache(); view.setDrawingCacheEnabled(false); return drawable; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight()); } @Override protected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); if (onDrawListener != null) { onDrawListener.onDrawListener(); } } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { //进度改变时调用 risk = getTargetProgress(seekBar) / (2 * oneLength) + 1; String popupText; if (barInterface != null) { int targetProgress = getTargetProgress(seekBar); popupText = barInterface.progressChangeCallBack(this, getProgress(), targetProgress); mPopupTextView.setText(popupText != null ? popupText : String.valueOf(targetProgress)); } if (mPopupStyle && mPopup != null) { showPopup(); mPopup.update(this, (int) getXPosition(getProgress(), mPopup.getContentView()), -(this.getHeight() + mPopup.getContentView().getMeasuredHeight() + mYLocationOffset), -1, -1); } else { hidePopup(); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { //进度条开始拖动的时候调用 showPopup(); centerText.setText(""); thumbDrawable = convertViewToDrawable(thumb); setThumb(thumbDrawable); } @Override public void onStopTrackingTouch(SeekBar seekBar) { //进度条停止拖动的时候调用 int targetProgress = getTargetProgress(seekBar); dodo(seekBar.getProgress(), targetProgress); if (mThumbStyle) { centerText.setText(risk + ""); } thumbDrawable = convertViewToDrawable(thumb); setThumb(thumbDrawable); } /** * 赋值+执行动画 * * @param progressText 当前滑动的点 * @param targetProgress 自动滑动到目标点 */ public void dodo(int progressText, int targetProgress) { AnimatorSet animation = new AnimatorSet(); ObjectAnimator progressAnimation = ObjectAnimator.ofInt(this, "progress", progressText, targetProgress); progressAnimation.setDuration(300); progressAnimation.setInterpolator(new AccelerateDecelerateInterpolator()); //增加动画监听 progressAnimation.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { hidePopup(); } @Override public void onAnimationCancel(Animator animation) { hidePopup(); } @Override public void onAnimationRepeat(Animator animation) { } }); animation.playTogether(progressAnimation); animation.start(); } /** * 选中回调 * * @param barInterface 回调监听 */ public void setSeekBarCallBack(SeekBarInterface barInterface) { this.barInterface = barInterface; } /** * 绘画监听接口 * * @param onDrawListener 绘画监听实现接口 */ public void setOnDrawListener(SeekBarOnDrawListener onDrawListener) { this.onDrawListener = onDrawListener; } /** * 是否显示pop * @param style 是否显示pop */ public void setPopupStyle(boolean style) { mPopupStyle = style; } private void initHintPopup() { String popupText = null; if (barInterface != null) { int targetProgress = getTargetProgress(this); popupText = barInterface.progressChangeCallBack(this, getProgress(), targetProgress); } LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); final View undoView = inflater.inflate(R.layout.popup, null); mPopupTextView = (TextView) undoView.findViewById(R.id.text); mPopupTextView.setText(popupText != null ? popupText : String.valueOf(getProgress())); mPopup = new PopupWindow(undoView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, false); mPopup.getContentView().measure(0, 0);//获取测量后的popWindow高度 mPopup.setAnimationStyle(R.style.fade_animation); } private void showPopup() { if (mPopupStyle) { mPopup.showAsDropDown(this, (int) getXPosition(getProgress(), mPopup.getContentView()), -(this.getHeight() + mPopup.getContentView().getMeasuredHeight() + mYLocationOffset)); } } private void hidePopup() { if (mPopup != null && mPopup.isShowing()) { mPopup.dismiss(); } } /** * 获取X坐标 * * @param progress 进度 * @param v 在seekBar上显示的View * @return X */ private float getXPosition(int progress, View v) { //seekBar总宽度包含ThumbOffset两边 float val = (((float) progress * ((float) getWidth())) / (float) getMax()); int textWidth = v.getMeasuredWidth(); float textCenter = (textWidth / 2.0f) + xOffset; return val - textCenter; } /** * 获取目标进度 * * @return 返回目标进度 */ private int getTargetProgress(SeekBar seekBar) { int targetProgress;//进度参数回调默认值 int proNow = seekBar.getProgress();//当前点 int yu = proNow % oneLength;//取余数 if ((proNow / oneLength) % 2 == 0) { //是否为满进度,满进度回退一格 targetProgress = proNow == getMax() ? proNow - oneLength : proNow + oneLength - yu; } else { targetProgress = proNow - yu; } return targetProgress; } /** * 设置推荐坐标 * * @param recommendPosition 显示在第几个点,从0开始 * @param ll_recommend */ public void setRecommendPosition(int recommendPosition, View ll_recommend) { int progress = oneLength + recommendPosition * 2 * oneLength; float x = getXPosition(progress, ll_recommend); LinearLayout.LayoutParams pa = (LinearLayout.LayoutParams) ll_recommend.getLayoutParams(); pa.setMargins((int) x, 0, 0, 0); ll_recommend.setLayoutParams(pa); }
public int getRisk() { return risk; } public void setRisk(int risk) { this.risk = risk; } /** * 是否显示Thumb数字 * @param mThumbStyle */ public void setThumbStyle(boolean mThumbStyle) { this.mThumbStyle = mThumbStyle; }}
使用方式:
private void initSeekbar() { recommend = 3; mSeekBar1.initThumb((mSeekBar1.getProgress() / (2 * mSeekBar1.oneLength)) + ""); mSeekBar1.setSeekBarCallBack(new SeekBarInterface() { @Override public String progressChangeCallBack(MyNiceSeekBar myNiceSeekBar, int progress, int targetProgress) { risk = myNiceSeekBar.getRisk(); myNiceSeekBar.setRisk(risk); //返回Pop上需要显示的字符串 return "节点" + risk; } }); mSeekBar1.setOnDrawListener(new SeekBarOnDrawListener() { @Override public void onDrawListener() { mSeekBar1.setRecommendPosition(recommend, ll_recommend); } }); }
2 0
- 自定义漂亮的seekBar,内带popwindow及指示器
- 带指示器的seekbar
- 【SeekBar】Android 自定义漂亮的SeekBar样式
- 自定义漂亮的Android SeekBar样式
- 自定义漂亮的Android SeekBar样式
- Android:自定义漂亮的SeekBar样式
- 自定义漂亮的Android SeekBar样式
- 自定义漂亮的Android SeekBar样式
- Android 自定义漂亮的Seekbar样式
- 自定义漂亮的Android SeekBar样式
- Android UI , QuickContactBadge, SeekBar, 自定义漂亮的Android SeekBar样式
- 自定义带刻度的seekbar
- 自定义带标尺的seekbar
- 自定义带刻度的SeekBar
- android5.0自定义seekbar指示器有白色的解决方案
- 自定义漂亮的Android SeekBar(拖动条)样式
- 安卓学习笔记---自定义漂亮的Android SeekBar样式
- 带数字显示的自定义SeekBar
- vim指令图
- spring多数据源配置
- 记录----一个连接oracle的jdbc测试
- 阿里中间件三大存储系统
- UVa11235 sparse-table RLE
- 自定义漂亮的seekBar,内带popwindow及指示器
- pull解析
- Spring动态多数据源实例Demo
- [bfs 分层图 字典序 最短路] BZOJ 2644 Pku3967 Ideal Path
- 260. Single Number III
- 166. Fraction to Recurring Decimal
- 24. Swap Nodes in Pairs
- Android ListView 图片异步加载和图片内存缓存
- eclipse安装反编译插件步骤