开始之前bb几句,虽然现在已经有类似的开源项目,但如果想真正理解它,还是要自己去手写一下,这不,趁着这两天空闲,公司项目不忙,就自己写了个demo,基本功能已完成,可能会有bug,回头再优化。
先说一下基本思路:
1.先创建一个类,继承View,先把刻度画出来。
2.再创建一个类,继承ViewGroup,这个类主要是控制内部尺子的滚动。
下面直接贴代码:
RulerView:
public class RulerView extends View {
private Paint mPaint;
private Path path;
private String color = "#FF4081";
//尺子Y轴水平基点
private int startYDraw;
//矫正刻度起始位置
private float firststep = 0;
//每个刻度起始位置
private float cachStep = 0;
//尺子长度
private int ruleSize = 501;
//一屏幕的刻度数
private int viewAll = 60;
private NumListener numListener;
private boolean isScrowComplent = false;
public RulerView(Context context) {
super(context);
initView();
}
public RulerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
public RulerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
mPaint = new Paint();
path = new Path();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(2);
mPaint.setColor(Color.parseColor(color));
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setTextSize(35);
}
protected void setScrowComplent(boolean isScrowComplent) {
this.isScrowComplent = isScrowComplent;
invalidate();
}
/**
* 滚动时调用(给RuleViewGroup调用,不要私自调用)
*
* @param changeX
*/
protected void setChangeX(float changeX) {
firststep = firststep + changeX;
invalidate();
}
/**
* 手动输入时,设置当前刻度值
*
* @param rule
*/
public void setNowRule(int rule) {
firststep = getWidth() / 2 - (getWidth() / viewAll * rule);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
startYDraw = (getHeight() / 2 - 20);
path.moveTo(getWidth() / 2, (startYDraw));
path.lineTo((getWidth() / 2) + 10, (startYDraw) - 30);
path.lineTo((getWidth() / 2) - 10, (startYDraw) - 30);
path.lineTo(getWidth() / 2, (startYDraw));
canvas.drawPath(path, mPaint);
//当起始位置超过中点时,则切换为中点,这样起始位置就不会跨过中点
if (firststep > getWidth() / 2) {
firststep = getWidth() / 2;
}
//-((getWidth()/viewAll)*(ruleSize-1)-(getWidth()/2))的计算结果为终点滑到中点时,起始位置的结果,
// 控制器不要超过此点,能保证终点不划过中点
if (firststep <= -((getWidth() / viewAll) * (ruleSize - 1) - (getWidth() / 2))) {
firststep = -((getWidth() / viewAll) * (ruleSize - 1) - (getWidth() / 2));
}
cachStep = firststep;
for (int i = 0; i < ruleSize; i++) {
if ((i % 5) == 0) {
canvas.drawLine(cachStep, startYDraw, cachStep, (startYDraw) + 80, mPaint);
canvas.drawText(i + "", cachStep, (startYDraw) + 120, mPaint);
} else {
canvas.drawLine(cachStep, startYDraw, cachStep, (startYDraw) + 55, mPaint);
}
//当前刻度在中点
if (cachStep <= (getWidth() / 2) && (cachStep + (getWidth() / viewAll)) >= (getWidth() / 2)) {
if (null != numListener) {
numListener.getnum(i);
//滚动完成
if (isScrowComplent) {
if(cachStep+(getWidth() / viewAll/2)>=(getWidth() / 2)){
setChangeX((getWidth() / 2)-cachStep);
}else{
setChangeX((getWidth() / 2)-(getWidth() / viewAll)-cachStep);
}
}
}
}
cachStep = cachStep + (getWidth() / viewAll);
}
}
public void setNumListener(NumListener numListener) {
this.numListener = numListener;
}
public interface NumListener {
void getnum(int num);
}
}
RulerViewGroup:
public class RulerViewGroup extends RelativeLayout implements Runnable {
private VelocityTracker mVelocityTracker;
//手指离开时的滚动速度
private float velocityX;
//当前的触摸点的X值
private float nowtouchX = 0;
//加速度
private int speedAdd = 1;
//单位时间
private int unitTime = 5;
//手指滑动方向
private boolean isLeft = false;
public RulerViewGroup(Context context) {
super(context);
intView();
}
public RulerViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
intView();
}
public RulerViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
intView();
}
private void intView() {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
boolean eventAddedToVelocityTracker = false;
final MotionEvent vtev = MotionEvent.obtain(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
nowtouchX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
((RulerView) getChildAt(0)).setScrowComplent(false);
try {
((RulerView) getChildAt(0)).setChangeX((event.getX() - nowtouchX));
Log.e("ChangeX", (event.getX() - nowtouchX) + "");
nowtouchX = event.getX();
} catch (Exception e) {
Log.e("RuleViewGroup", "布局错误");
}
//计算实时滑动速度
mVelocityTracker.addMovement(vtev);
eventAddedToVelocityTracker = true;
mVelocityTracker.computeCurrentVelocity(unitTime, 1000);
velocityX = mVelocityTracker.getXVelocity(event.getPointerId(0));
//用于run方法判断加速度的正负
if (velocityX >= 0) {
isLeft = false;
} else {
isLeft = true;
}
break;
case MotionEvent.ACTION_UP:
//启动惯性滚动
postDelayed(this, unitTime);
break;
case MotionEvent.ACTION_CANCEL:
releaseVelocityTracker();
break;
default:
break;
}
if (!eventAddedToVelocityTracker) {
mVelocityTracker.addMovement(vtev);
}
vtev.recycle();
return true;
}
@Override
public void run() {
int x = (int) (velocityX * unitTime / 5);
if (isLeft) {
velocityX = velocityX + speedAdd;
if (velocityX >= 0) {
velocityX = 0;
}
} else {
velocityX = velocityX - speedAdd;
if (velocityX <= 0) {
velocityX = 0;
}
}
try {
((RulerView) getChildAt(0)).setChangeX(x);
} catch (Exception e) {
Log.e("RuleViewGroup", "布局错误");
}
if (velocityX != 0) {
postDelayed(this, unitTime);
} else {
try {
((RulerView) getChildAt(0)).setScrowComplent(true);
} catch (Exception e) {
Log.e("RuleViewGroup", "布局错误");
}
}
}
//释放VelocityTracker
private void releaseVelocityTracker() {
if (null != mVelocityTracker) {
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
}
下面是布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/num"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="请输入刻度值"
android:inputType="number"
android:text=""
android:textSize="20dp" />
<TextView
android:id="@+id/setnum"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="number"
android:text=""
android:textSize="30dp" />
<Button
android:id="@+id/submit"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="提交" />
</LinearLayout>
<com.example.myapplication.touch.RulerViewGroup
android:layout_width="match_parent"
android:layout_height="200dp">
<com.example.myapplication.touch.RulerView
android:id="@+id/ruler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</com.example.myapplication.touch.RulerViewGroup>
</LinearLayout>
以上代码放到项目里可以直接用
image.png
网友评论