模仿某理财界面做了一个类似尺子的控件
步骤:
1,重写三个构造方法
2,用画笔和canvas分别画三种线条(底部线条,当前刻度,所有刻度)
3,重写
onTouchEvent,根据移动的距离重绘
4,设置手势识别器从而增加滚动惯性,滚动的时候用handler重绘控件
5,设置回调让主界面实时更新选中的刻度。
Talk is cheap,show you my code.
自定义尺子代码:
package com.ouyang.qqui.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
/**
* Create by oy 2017/8/15 15:35.
*/
public class Ruler extends View {
//画笔
//底部
private Paint mBorderPaint = new Paint();
//刻度
private Paint mScaleMarkPaint = new Paint();
//当前
private Paint mCurrentMarkPaint = new Paint();
//高
private int mViewHeight;
//宽
private int mViewWidth;
//每份的宽度
private int partWith;
//中间数
private int mCenterNum;
//最后按下的X坐标
private float mLastDownX;
private Context context;
private Scroller scroller;
private GestureDetector gestureDetector;
public interface OnChangeListener{
void onChange(int mCenterNum);
}
private OnChangeListener onChangeListener;
public void setOnChangeListener(OnChangeListener onChangeListener){
this.onChangeListener = onChangeListener;
}
private int ON_FLING = 1;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
//判断是否滚动完成,true说明滚动尚未完成
boolean isFinished = scroller.computeScrollOffset();
//获取mScroller当前水平滚动的位置
int curX = scroller.getCurrX();
float v = (curX - mLastDownX)/partWith;
mLastDownX = curX;
//设置中间数然后重绘
mCenterNum +=v;
invalidate();
if(isFinished){
//未完成就一直重绘
handler.sendEmptyMessage(ON_FLING);
}
}
};
private float distanceX;
public Ruler(Context context) {
this(context,null);
}
public Ruler(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public Rule(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化view
this.context = context;
initView();
}
private void initView() {
gestureDetector = new GestureDetector(context, simpleOnGestureListener);
gestureDetector.setIsLongpressEnabled(false);
scroller = new Scroller(context);
//设置底部画笔
mBorderPaint.setColor(Color.GRAY);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setStrokeWidth(2);
//所有刻度
mScaleMarkPaint.setColor(Color.GRAY);
mScaleMarkPaint.setStyle(Paint.Style.FILL);
mScaleMarkPaint.setStrokeWidth(3);
mScaleMarkPaint.setTextSize(20);
//当前刻度
mCurrentMarkPaint.setColor(0xfffca23a);
mCurrentMarkPaint.setStyle(Paint.Style.FILL);
mCurrentMarkPaint.setStrokeWidth(3);
mCurrentMarkPaint.setTextSize(20);
}
//手势识别器
private GestureDetector.SimpleOnGestureListener simpleOnGestureListener = new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//最大和最小的整型数 int
final int minX = -0x7fffffff;
final int maxX = 0x7fffffff;
//惯性滑动
//指定起点(startX,startY),滑动(velocityX,velocityY),最大和最小坐标
//fling(int startX, int startY, int velocityX, int velocityY,
// int minX, int maxX, int minY, int maxY):
//设置滚动惯性
scroller.fling(0, 0, (int)-velocityX, 0, minX, maxX, 0, 0);
//根据惯性重绘界面
handler.sendEmptyMessage(ON_FLING);
mLastDownX = 0;
return true;
}
};
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取view的宽高,作为绘制线条用
mViewHeight = getMeasuredHeight();
mViewWidth = getMeasuredWidth();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//限制范围
int maxNum = 1000;
int minNum = -1000;
if (mCenterNum>maxNum){
mCenterNum = maxNum;
}else if (mCenterNum<minNum){
mCenterNum = minNum;
}
//绘制底部线条
drawBottomLine(canvas);
//绘制刻度
drawScaleLine(canvas);
//绘制当前刻度
drawCurrentLine(canvas);
}
private void drawCurrentLine(Canvas canvas) {
//绘制当前刻度
canvas.drawLine(mViewWidth/2, mViewHeight,mViewWidth/2, mViewHeight-25, mCurrentMarkPaint);
}
private void drawScaleLine(Canvas canvas) {
//总刻度为-10到110,左边绘制完了绘制右边
//将总长度绘制为20等份,然后每隔10份绘制一条长的
partWith = (mViewWidth-30)/30;
//最小值为-10,最大值为100,计数器为count
int count = 0;
//左边距
int left = mViewWidth/2;
while (left>0){
//左边距等于中间宽度减去距离*数量
left = mViewWidth/2 - partWith * count;
//左边数字等于中间数字减去数量
int leftNum = mCenterNum - count;
String leftText = String.valueOf(leftNum);
if(leftNum % 10 == 0) {
//线条
canvas.drawLine(left, mViewHeight - 25, left, mViewHeight - 1, mScaleMarkPaint);
//文字
canvas.drawText(leftText,left-3, mViewHeight -35, mCurrentMarkPaint);
}else {
//线条
canvas.drawLine(left, mViewHeight - 10, left, mViewHeight - 1, mScaleMarkPaint);
}
count++;
}
count = 0;
int right = mViewWidth/2;
while (right < mViewWidth ){
//右边距
right = mViewWidth/2 + partWith * count;
//右边数字
int rightNum = mCenterNum + count;
String rightText = String.valueOf(rightNum);
if(rightNum % 10 == 0) {
//线条
canvas.drawLine(right, mViewHeight - 25, right, mViewHeight - 1, mScaleMarkPaint);
//文字
canvas.drawText(rightText,right-3, mViewHeight -35, mCurrentMarkPaint);
}else {
canvas.drawLine(right, mViewHeight - 10, right, mViewHeight - 1, mScaleMarkPaint);
}
count++;
}
if (onChangeListener!=null){
onChangeListener.onChange(mCenterNum);
}
}
private void drawBottomLine(Canvas canvas) {
//绘制底部线条,高度不变,宽度从0到view的总宽
canvas.drawLine(0, mViewHeight, mViewWidth, mViewHeight, mBorderPaint);
}
//重写触摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
//强制结束本次滑屏操作
scroller.forceFinished(true);
mLastDownX =(int) event.getX();
break;
case MotionEvent.ACTION_MOVE:
//随着移动而重绘
float moveX = event.getX();
//移动的距离叠加
distanceX += (moveX - mLastDownX)/partWith;
mLastDownX = moveX;
//当移动的距离大于1或小于-1的时候移动一格
if (distanceX >1|| distanceX <-1){
mCenterNum -= (int) distanceX;
distanceX = 0;
}
invalidate();
break;
}
//调用手势识别器的触摸监听是为了增加滑动惯性
gestureDetector.onTouchEvent(event);
return true;
}
}
主界面布局代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:materialdesign="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.ouyang.qqui.view.Ruler
android:id="@+id/ruler"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginBottom="50dp"/>
<TextView
android:id="@+id/tv_ruler"
android:layout_width="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_height="wrap_content"
android:textSize="15sp"
android:text=""
android:layout_marginBottom="20dp"/>
</RelativeLayout>
ruler.setOnChangeListener(new Ruler.OnChangeListener() {
@Override
public void onChange(int mCenterNum) {
String s = "我要出借"+mCenterNum+"元";
tvRule.setText(s);
}
});