仿拉钩薪资选择器

我们不缺少想法,只是缺少开始的勇气

之前有个同学问我拉钩的薪资选择怎么做,网上资料也找不到。说实话之前我倒是没有注意过拉钩的薪资范围选择是怎么样的。啥也别说了,去下一个看看呗!看到效果一脸懵逼啊,真的是一点想法都没有,当时事情也比较多,所以也就没有深究,有点辜负同学对我的信任了。

这段时间趁着有空,打算把自定义view重新温故一下,就想到了之前的需求。那咱也仿制一个呗,人家都实现了,那我肯定也是可以实现的。由于资质有限,花了大概两天的时间才造出一个90分的demo,废话不多说,先来看下效果。

薪资范围.gif

什么?你还没看够,那你下下来慢慢看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>
这时候你看到的效果应该是这样子的

view.png
-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就好

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容