可以滑动定值的控件,尺寸工具类
需要的工具类:
1.SizeUtil.java
import android.app.Activity; import android.content.Context; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.View; import android.view.Window; import android.view.WindowManager; /** * 尺寸相关工具类 * 1.dpi转px * 2.px转dp * 3.sp转px * 4.px转sp * 5.onCreate中强行获取View的宽高 * 6.获取屏幕的宽度px * 7.获取屏幕的高度px * 8.获取状态栏高度 * 9.获取状态栏高度+标题栏(ActionBar)高度 */ public class SizeUtil { //dpi转px public static float Dp2Px(Context context, float dpi) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpi, context.getResources().getDisplayMetrics()); } //px转dp public static float Px2Dp(Context context, float px) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px, context.getResources().getDisplayMetrics()); } //sp转px public static float Sp2Px(Context context, float sp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics()); } //px转sp 代码中设置字体大小时这个 public static float Px2Sp(Context context, float px) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px, context.getResources().getDisplayMetrics()); } //onCreate中强行获取View的宽高 public static int[] forceGetViewSize(View view) { int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); view.measure(widthMeasureSpec, heightMeasureSpec); return new int[]{widthMeasureSpec, heightMeasureSpec}; } //获取屏幕的宽度px public static int getDeviceWidth(Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics();// 创建了一张白纸 windowManager.getDefaultDisplay().getMetrics(outMetrics);// 给白纸设置宽高 return outMetrics.widthPixels; } //获取屏幕的高度px public static int getDeviceHeight(Context context) { WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics();// 创建了一张白纸 windowManager.getDefaultDisplay().getMetrics(outMetrics);// 给白纸设置宽高 return outMetrics.heightPixels; } //获取状态栏高度 public int getStatusBarHeight(Context context) { int result = 0; int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; } //获取状态栏高度+标题栏(ActionBar)高度 public static int getTopBarHeight(Activity activity) { return activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop(); } }
2.RangeEntity.java
/** * 范围选择的实体类 */ public class RangeEntity { private String mTitle; private Object mValue; public RangeEntity(String title, int value) { mTitle = title; mValue = value; } public String getTitle() { return mTitle; } public void setTitle(String title) { mTitle = title; } public Object getValue() { return mValue; } public void setValue(int value) { mValue = value; } }
3.范围值的改变监听 OnRangeChangedListener
/** * 选择值范围的滑动监听 */ public interface OnRangeChangedListener { void selected(int start, int end); }
4.自定义类:RangeBar
import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; /** * 滑动定范围值 */ public class RangeBar extends View { private int mHeight = 0; // 组件高度 private int mWidth = 0; // 组件宽度 /** * 圆形的半径 */ private int mCircleRadius; /** * 线条的颜色 */ private int mLineColor; /** * 选中圆形的颜色 */ private int mCenterColor; private Paint mPaint; private int mTextSize; //文字大小 private float mSingleWidth = 0; //每个刻度的宽度 private OnRangeChangedListener mListener; private float mStartX; //起始点坐标 private float mEndX; //终止点坐标 private int mBeginValue = 0; // 计数开始的值 private int mFinishValue = 0; // 计数结束的值 private int mStartValue = 0; //开始的值 private int mEndValue = 0; //结束的值 private String mIndex = ""; //后缀 private float mStartProgress = 0; //开始的进度 private float mEndProgress = 0; // 结束的进度 public RangeBar(Context context) { this(context, null); } public RangeBar(Context context, AttributeSet attrs) { super(context, attrs); init(); } //设置后缀 public void setIndex(String index) { mIndex = index; } //设置起始值 public void setBeginValue(int beginValue) { mBeginValue = beginValue; mStartValue = mBeginValue; mStartProgress = 0; } //设置结束值 public void setFinishValue(int finishValue) { mFinishValue = finishValue; mEndValue = mFinishValue; mEndProgress = 1.0f; } //设置开始的初始值 public void setInitValue(int startValue, int endValue) { mStartValue = startValue; mStartProgress = (mStartValue - mBeginValue) * 1.0f / (mFinishValue - mBeginValue); mEndValue = endValue; mEndProgress = (mEndValue - mBeginValue) * 1.0f / (mFinishValue - mBeginValue); getRightPosition(); } //根据百分比计算开始的坐标和结束的坐标 private void getRightPosition() { mStartX = mCircleRadius * 2 + ((int) (mStartProgress * 100)) * mSingleWidth; //起点坐标 mEndX = mCircleRadius * 2 + ((int) (mEndProgress * 100)) * mSingleWidth; invalidate(); } //设置范围监听器 public void setRangeChangeListener(OnRangeChangedListener listener) { mListener = listener; } private void init() { mCircleRadius = (int) SizeUtil.Dp2Px(getContext(), 10);//圆形的半径 mCenterColor = getResources().getColor(R.color.colorPoint);//圆形的颜色 mLineColor = getResources().getColor(R.color.splitGrayColor);//线条的颜色 mTextSize = (int) SizeUtil.Sp2Px(getContext(), 15); mPaint = new Paint(); mPaint.setDither(true); mPaint.setAntiAlias(true); } private boolean isStartMoving = false; private boolean isEndMoving = false; @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); float x = event.getX(); float y = event.getY(); switch (action) { case MotionEvent.ACTION_DOWN: if ((Math.abs(mStartX - mCircleRadius - x) <= mCircleRadius)) { isStartMoving = true; break; } if ((Math.abs(mEndX + mCircleRadius - x) <= mCircleRadius)) { isEndMoving = true; break; } break; case MotionEvent.ACTION_UP: isStartMoving = false; isEndMoving = false; break; case MotionEvent.ACTION_MOVE: if (isStartMoving) { mStartX = x; if (mStartX >= mEndX - mSingleWidth) { mStartX = mEndX - mSingleWidth; Log.i("SingleWidth", mSingleWidth + ""); } if (mStartX - mCircleRadius * 2 < 0) { mStartX = mCircleRadius * 2; } Log.i("StartX", mStartX + ""); } if (isEndMoving) { mEndX = x; if (mEndX < mStartX + mSingleWidth) { mEndX = mStartX + mSingleWidth; } if (mEndX + mCircleRadius * 2 > mWidth) { mEndX = mWidth - mCircleRadius * 2; } Log.i("EndX", mEndX + ""); } getRightValue();//获取正确的值 invalidate(); break; } return true; } //根据坐标获取正确的值 public void getRightValue() { getRightProgress(); mStartValue = (int) (mBeginValue + (mFinishValue - mBeginValue) * mStartProgress); mEndValue = (int) (mBeginValue + (mFinishValue - mBeginValue) * mEndProgress); if (mStartValue == mEndValue) { if (isStartMoving) { mStartValue -= 1; } else if (isEndMoving) { mEndValue += 1; } } Log.i("Value", mStartValue + ":" + mEndValue); } //根据坐标获取正确的进度 public void getRightProgress() { mStartProgress = (mStartX - 2 * mCircleRadius) * 1.0f / mSingleWidth / 100; mEndProgress = (mEndX - 2 * mCircleRadius) * 1.0f / mSingleWidth / 100; Log.i("Progress", mStartProgress + ":" + mEndProgress); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = MeasureSpec.getSize(widthMeasureSpec); mHeight = (int) (SizeUtil.Dp2Px(getContext(), 30) + getPaddingTop() + getPaddingBottom()); setMeasuredDimension(mWidth, mHeight); mSingleWidth = ((mWidth * 1.0f - 4 * mCircleRadius) / 100); //每一个刻度的宽度 getRightPosition(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制圆角矩形 -5与+5 控制着中间灰色线条的宽度 RectF lineRect = new RectF(0, mHeight / 2 - 5, mWidth, mHeight / 2 + 5); mPaint.setStyle(Paint.Style.FILL); mPaint.setStrokeWidth(1);//设置线条的线宽 mPaint.setColor(mLineColor); canvas.drawRoundRect(lineRect, 20, 20, mPaint);//绘制线条 //绘制中间的线,选择的范围的线 mPaint.setColor(mCenterColor); RectF doneRect = new RectF(mStartX - mCircleRadius / 2, mHeight / 2 - 10, mEndX + mCircleRadius / 2, mHeight / 2 + 10); canvas.drawRoundRect(doneRect, 20, 20, mPaint); //按照进度绘制位置 mPaint.setStyle(Paint.Style.STROKE);//空心圆 mPaint.setColor(mCenterColor); mPaint.setStrokeWidth(5);//设置圆形的线宽 canvas.drawCircle(mStartX - mCircleRadius, mHeight / 2, mCircleRadius, mPaint); canvas.drawCircle(mEndX + mCircleRadius, mHeight / 2, mCircleRadius, mPaint); mPaint.setTextSize(25);//设置圆心里文本的大小, SizeUtil.Dp2Px(context, 11)比较好 if (mListener != null) { mListener.selected(mStartValue, mEndValue); } String start = mStartValue + mIndex; String end = mEndValue + mIndex; Rect startText = new Rect(); Rect endText = new Rect(); mPaint.getTextBounds(start, 0, start.length(), startText); mPaint.getTextBounds(end, 0, end.length(), endText); mPaint.setStrokeWidth(2);//设置绘制圆心里文本的线宽 //绘制文字 mPaint.setColor(getResources().getColor(R.color.colorText));//设置圆形中文本的显示颜色 canvas.drawText(start, mStartX - mCircleRadius - (startText.right - startText.left) / 2, mHeight / 2 - (startText.bottom + startText.top) / 2, mPaint); canvas.drawText(end, mEndX + mCircleRadius - (endText.right + endText.left) / 2, mHeight / 2 - (endText.bottom + endText.top) / 2, mPaint); } }
使用的值 values/colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- 选中的范围的线条的颜色 --> <color name="colorPoint">#FF4956</color> <!-- 圆形上面尺度文本的颜色 --> <color name="colorText">#FF4956</color> <!-- 灰色作为线条的颜色 --> <color name="splitGrayColor">#cccccc</color> </resources>
使用方法:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.timepigtest.RangeBar android:id="@+id/main_rengae" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true"/> </RelativeLayout>
代码:
mRangeBar = (RangeBar) findViewById(R.id.main_rengae); mRangeBar.setBeginValue(20);//最小值 mRangeBar.setFinishValue(50);//最大值 //mRangeBar.setIndex("%");设置圆心里的值带百分号 mRangeBar.setInitValue(23, 40);//初始化的值 mRangeBar.setRangeChangeListener(new OnRangeChangedListener() { @Override public void selected(int start, int end) { Log.i("Range:", start + ":" + end);//滑动改变的监听,得到选择的值的范围 } });
效果图: 可以滑动,如果下方需要值显示用线性布局设置权重写几个TextView就O了