我们不缺少想法,只是缺少开始的勇气
之前有个同学问我拉钩的薪资选择怎么做,网上资料也找不到。说实话之前我倒是没有注意过拉钩的薪资范围选择是怎么样的。啥也别说了,去下一个看看呗!看到效果一脸懵逼啊,真的是一点想法都没有,当时事情也比较多,所以也就没有深究,有点辜负同学对我的信任了。
这段时间趁着有空,打算把自定义view重新温故一下,就想到了之前的需求。那咱也仿制一个呗,人家都实现了,那我肯定也是可以实现的。由于资质有限,花了大概两天的时间才造出一个90分的demo,废话不多说,先来看下效果。
什么?你还没看够,那你下下来慢慢看http://fir.im/kbrf, 接下来我来讲一下具体的实现思路:之前也想过在ProgressBar的基础上来实现,不过最后放弃了。条条大路通罗马,方法肯定不止一种,大家不要局限于我的思想。
-1- 不管三七二十一,先把view做出来,有个样子先,其他的再慢慢做
这一步非常简单,图片资料可以从拉钩的app中解压出来
<pre>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<View
android:id="@+id/view_progress"
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@color/progress_select"
/>
<LinearLayout
android:id="@+id/slide_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
>
<TextView
android:id="@+id/tv_salary_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_number_unselect"
android:gravity="center"
android:paddingBottom="6dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:paddingTop="2dp"
android:text="1K"
android:textColor="@android:color/white"
android:textSize="12sp"
/>
<View
android:layout_width="2dp"
android:layout_height="12dp"
android:layout_marginTop="14dp"
android:background="@color/progress_nomal"
/>
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/arrow"/>
</LinearLayout>
<!--左边滑块-->
<LinearLayout
android:id="@+id/slide_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:gravity="center"
android:orientation="vertical"
>
<TextView
android:id="@+id/tv_salary_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_number_unselect"
android:gravity="center"
android:paddingBottom="6dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:paddingTop="2dp"
android:text="100K"
android:textColor="@android:color/white"
android:textSize="12sp"
/>
<View
android:layout_width="2dp"
android:layout_height="12dp"
android:layout_marginTop="14dp"
android:background="@color/progress_nomal"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/arrow"
/>
</LinearLayout>
</RelativeLayout>
</pre>
这时候你看到的效果应该是这样子的
-2- 接下来就是处理左右两边view的滑动
关于这个需求我立马就想到了ViewDragHelper,简直就是处理滑动的利器,还没有学习的赶紧学习下,具体可参考 http://blog.csdn.net/lmj623565791/article/details/46858663 我捡Demo中用到的来讲一下
- 创建实例
mViewDragHelper = ViewDragHelper.create(this, 1.0f,new ViewDragHelper.Callback() {});
三个参数分别为Viewgroup,灵敏度,回调 - 触摸相关方法
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
是否拦截触摸,触摸事件处理都交给ViewDragHelper处理就好 - 回调方法(我只捡Demo中用到的说)
tryCaptureView 捕捉View,说白了就是指定哪些子View的触摸交给ViewDragHelper来处理。
clampViewPositionHorizontal 对child移动的水平边界进行控制
clampViewPositionVertical 对child移动的竖直边界进行控制
getViewHorizontalDragRange 返回拖拽的范围,当子view中包含有可点击的view时此方法必须设置
onViewCaptured 当captureview被捕获时回调
onViewPositionChanged 当captureview的位置发生改变时回调
onViewReleased 手指抬起回调
onViewDragStateChanged 当ViewDragHelper状态发生变化时回调
完成这一步之后你可以看到两边的子View可以滑动了
-3- 滑动范围
仔细观察可以发现右边view的滑动范围是左边view到最右边,左边view同理。看了上面的回调方法自然知道范围在clampViewPositionHorizontal 和clampViewPositionVertical 中设置,还需要在手指抬起时记录下当前的位置
/**
* 对移动的边界进行控制
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
int leftBound = currentPositionLeft;
int rightBound = currentPotionRight == 0 ? getWidth() - slideRight.getWidth() : currentPotionRight - slideRight.getWidth();
int newLeft = Math.min(Math.max(left, leftBound), rightBound);
return newLeft;
}
/**
* 设置上下不能滑动
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return 0;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
if (releasedChild == slideLeft) {
currentPositionLeft = slideLeft.getLeft();
}
if (releasedChild == slideRight) {
currentPotionRight = slideRight.getRight();
}
}
-4- 选中状态
可以看到无论是移动左边的view还是右边的view,薪资的背景都是需要改变的。这时候你肯定会笑着说“这还不容易吗”,设置TextView的背景就好了。的确是这么做的
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
switch (state) {
//不拖拽状态
case ViewDragHelper.STATE_IDLE:
salaryLower.setBackgroundResource(R.drawable.bg_number_unselect);
salaryUpper.setBackgroundResource(R.drawable.bg_number_unselect);
break;
//拖拽中
case ViewDragHelper.STATE_DRAGGING:
if (mViewDragHelper.getCapturedView() == slideLeft) {
salaryLower.setBackgroundResource(R.drawable.bg_number_seleted);
} else {
salaryUpper.setBackgroundResource(R.drawable.bg_number_seleted);
}
break;
//view设置中
case ViewDragHelper.STATE_SETTLING:
break;
}
}
当你沾沾自喜时,运行起来却发现手指释放的时候view永远是弹回刚开始时的位置。(去他妈的,怎么搞的),这东西困扰了我好久,后来仔细看setBackgroundResource的源码才发现会调用requestLayout重新回调onLayout,而这边记录的恰恰只有刚开始时的位置,不回去才怪呐。这里需要记录滑到的位置重写onLayout方法。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (isFirst) {
mLeftLower = slideLeft.getLeft();
mTopLower = slideLeft.getTop();
mLeftUpper = slideRight.getLeft();
mTopUpper = slideRight.getTop();
isFirst = false;
}
//设置view的位置
slideLeft.layout(mLeftLower, mTopLower, mLeftLower + slideLeft.getMeasuredWidth(), mTopLower + slideLeft.getMeasuredHeight());
slideRight.layout(mLeftUpper, mTopUpper, mLeftUpper + slideRight.getMeasuredWidth(), mTopUpper + slideRight.getMeasuredHeight());
}
-5- 改变TextView的薪资显示
聪明的你应该知道在onViewPositionChanged 方法中实现,仔细观察可以发现总共有35个薪资段
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if (changedView == slideLeft) {
int valuesLeft = (int) (left / unitLong);
if (valuesLeft < 25) {
currentSalaryLeft = valuesLeft + 1;
} else if (valuesLeft < 30) {
switch (valuesLeft){
case 25:
currentSalaryLeft = 30;
break;
case 26:
currentSalaryLeft = 35;
break;
case 27:
currentSalaryLeft = 40;
break;
case 28:
currentSalaryLeft = 45;
break;
case 29:
currentSalaryLeft = 50;
break;
}
} else {
switch (valuesLeft){
case 30:
currentSalaryLeft = 60;
break;
case 31:
currentSalaryLeft = 70;
break;
case 32:
currentSalaryLeft = 80;
break;
case 33:
currentSalaryLeft = 90;
break;
case 34:
currentSalaryLeft = 100;
break;
}
}
pathLeft = left;
mLeftLower = slideLeft.getLeft();
salaryLower.setText(currentSalaryLeft + "K");
}
if (changedView == slideRight) {
int valuesRight = (int) (left / unitLong);
if (valuesRight < 25) {
currentSalaryRight = valuesRight + 1;
} else if (valuesRight < 30) {
switch (valuesRight){
case 25:
currentSalaryRight = 30;
break;
case 26:
currentSalaryRight = 35;
break;
case 27:
currentSalaryRight = 40;
break;
case 28:
currentSalaryRight = 45;
break;
case 29:
currentSalaryRight = 50;
break;
}
} else {
switch (valuesRight){
case 30:
currentSalaryRight = 60;
break;
case 31:
currentSalaryRight = 70;
break;
case 32:
currentSalaryRight = 80;
break;
case 33:
currentSalaryRight = 90;
break;
case 34:
currentSalaryRight = 100;
break;
}
}
pathRight = left;
mLeftUpper = slideRight.getLeft();
salaryUpper.setText(currentSalaryRight + "K");
}
if (salaryProgressListener != null) {
salaryProgressListener.salaryProgress(currentSalaryLeft, currentSalaryRight);
}
postInvalidate();
}
-6- 显示绿色的薪资范围
- 自定义ViewGroup默认不调用onDraw方法,可以通过setBackgroud触发
- PathMeasure可以用来截取Path片段
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
mPath.reset();
dstPath.reset();
mPath.moveTo(viewProgress.getLeft(), viewProgress.getBottom() - viewProgress.getMeasuredHeight() / 2);
mPath.lineTo(viewProgress.getRight(), viewProgress.getBottom() - viewProgress.getMeasuredHeight() / 2);
mPathMeasure = new PathMeasure(mPath, false);
mPathMeasure.getSegment(pathLeft, pathRight, dstPath, true);
canvas.drawPath(dstPath, mPaint);}
Github地址https://github.com/liulingfeng/SalaryProgress 高兴点个Star就好