高仿Instagram拖動(dòng)條

之前做項(xiàng)目的時(shí)候,有個(gè)圖片編輯頁面,用到拖動(dòng)條添加編輯效果。老板很喜歡Instagram那種拖動(dòng)條的效果,0點(diǎn)從中間開始衰絮,左減右增,也要做成這樣咆畏。Android原生的SeekBar燃异,是從左邊開始,一直往右邊增加的夯膀,不能將起點(diǎn)設(shè)在中間诗充。然后在GitHub上找了幾遍,也沒有找到符合要求的诱建,只能自己實(shí)現(xiàn)了蝴蜓。

先看一下效果圖:
ccc.gif
思路:

1、一根線俺猿,一個(gè)活動(dòng)圓

2茎匠、線分三段,活動(dòng)圓未到達(dá)的前后兩段押袍,活動(dòng)圓掃過的中間段

3诵冒、監(jiān)聽觸摸事件,刷新活動(dòng)圓的位置谊惭,和三段線

具體實(shí)現(xiàn)

1汽馋、資源初始化

 private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MiddleSeekBar, defStyleAttr, R.style.MiddleSeekBar);
        mThumbRadius = a.getDimensionPixelSize(R.styleable.MiddleSeekBar_MB_ThumbRadius, 0);
        mThumbColor = a.getColor(R.styleable.MiddleSeekBar_MB_ThumbColor, 0);
        mTextColor = a.getColor(R.styleable.MiddleSeekBar_MB_TextColor, 0);
        mProgressColor = a.getColor(R.styleable.MiddleSeekBar_MB_ProgressColor, 0);
        mProgressBackgroundColor = a.getColor(R.styleable.MiddleSeekBar_MB_ProgressBackgroundColor, 0);
        mTextSize = a.getDimensionPixelSize(R.styleable.MiddleSeekBar_MB_TextSize, 0);
        mProgressWidth = a.getDimensionPixelOffset(R.styleable.MiddleSeekBar_MB_ProgressWidth, 0);
        a.recycle();

        //初始化提示文字畫筆
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setColor(mTextColor);
        //初始化進(jìn)度條畫筆
        mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
        mProgressPaint.setStyle(Paint.Style.STROKE);
        mProgressPaint.setStrokeWidth(mProgressWidth);
        //初始化活動(dòng)圓畫筆
        mThumbShadowRadius = (int) (getResources().getDisplayMetrics().density * THUMB_SHADOW);
        mYOffset = (int) (getResources().getDisplayMetrics().density * Y_OFFSET);
        if(!isInEditMode()) {
            ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, mThumbPaint);
            mThumbPaint.setShadowLayer(mThumbShadowRadius, 0, mYOffset, KEY_SHADOW_COLOR);
        }
        mThumbPaint.setColor(mThumbColor);
    }

2、測(cè)量

  @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
        //suggestHeight算出拖動(dòng)條的高度
        int suggestHeight = (int) (3 * mThumbRadius + mThumbShadowRadius - fontMetrics.top + fontMetrics.bottom + getPaddingTop() + getPaddingBottom());
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                resolveSizeAndState(suggestHeight, heightMeasureSpec, 0));
    }

3圈盔、繪制

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        //設(shè)置最左邊的起始點(diǎn)
        mStartPoint.set(getPaddingLeft() + mThumbRadius, h - getPaddingBottom() - mThumbRadius - mThumbShadowRadius);
        mProgressLength = w - getPaddingLeft() - getPaddingRight() - 2 * mThumbRadius;
        //設(shè)置活動(dòng)圓作用區(qū)域的長方形
        mThumbRect.set(mStartPoint.x + mProgressLength * mThumbRatio - HIT_SCOPE_RATIO * mThumbRadius, mStartPoint.y - HIT_SCOPE_RATIO * mThumbRadius,
                mStartPoint.x + mProgressLength * mThumbRatio + HIT_SCOPE_RATIO * mThumbRadius, mStartPoint.y + HIT_SCOPE_RATIO * mThumbRadius);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        int y = mStartPoint.y;
        int firstX = mStartPoint.x;//最左邊點(diǎn)
        int secondX = mStartPoint.x + mProgressLength/2;//中間點(diǎn)
        int thirdX = (int) mThumbRect.centerX();//活動(dòng)圓所在點(diǎn)

        //draw progress將進(jìn)度條分成三段豹芯,前段沒有到達(dá)時(shí)顯示背景色,中段顯示進(jìn)度顏色驱敲,后端沒有到達(dá)時(shí)顯示背景色
        mProgressPaint.setColor(mProgressBackgroundColor);
        canvas.drawLine(firstX, y, secondX<thirdX?secondX:thirdX, y, mProgressPaint);
        mProgressPaint.setColor(mProgressColor);
        if (secondX < thirdX){
            canvas.drawLine(secondX, y, thirdX, y, mProgressPaint);
        }else {
            canvas.drawLine(thirdX, y, secondX, y, mProgressPaint);
        }
        mProgressPaint.setColor(mProgressBackgroundColor);
        canvas.drawLine(thirdX>secondX?thirdX:secondX, y, firstX + mProgressLength, y, mProgressPaint);

        //畫活動(dòng)圓
        canvas.drawCircle(thirdX, y, mThumbRadius, mThumbPaint);

        //畫提示文字
        mPromptString = ratio2String(mThumbRatio);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText(mPromptString, mThumbRect.centerX(), mThumbRect.top - mThumbRadius, mTextPaint);
    }

4铁蹈、觸摸事件

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //判斷觸摸點(diǎn)在活動(dòng)圓方形作用域內(nèi)
                if (mThumbRect.contains(x, y)) {
                    selectInfo.pointerId = event.getPointerId(0);
                    selectInfo.isCaptured = true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (selectInfo.isCaptured) {
                    if (moveThumb(x)) return false;
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                selectInfo.invalid();
                break;
        }
        if (selectInfo.isCaptured) {
            if(mOnSeekBarChangeListener!=null){
                mOnSeekBarChangeListener.onProgressChanged(this, mThumbRatio);
            }
            invalidate();
        }
        //讓父View的 onInterceptTouchEvent(MotionEvent)失效
        if(ViewCompat.isAttachedToWindow(this)){
            getParent().requestDisallowInterceptTouchEvent(selectInfo.isCaptured);
        }
        return selectInfo.isCaptured;
    }


    private boolean moveThumb(float x) {
        if (x > mStartPoint.x) {
            mThumbRatio = (x - mStartPoint.x) / mProgressLength;
            if (mThumbRatio > 1) {
                mThumbRatio = 1;
                return true;
            }
            float offsetX = x - mThumbRect.centerX();
            //活動(dòng)圓位置進(jìn)行偏移調(diào)整
            mThumbRect.offset(offsetX, 0);
        }
        return false;
    }
總結(jié)

就這樣,一個(gè)中間為起點(diǎn)可以兩邊拖動(dòng)的拖動(dòng)條實(shí)現(xiàn)了众眨。
完整代碼GitHub

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末握牧,一起剝皮案震驚了整個(gè)濱河市便锨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌我碟,老刑警劉巖放案,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異矫俺,居然都是意外死亡吱殉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門厘托,熙熙樓的掌柜王于貴愁眉苦臉地迎上來友雳,“玉大人,你說我怎么就攤上這事铅匹⊙荷蓿” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵包斑,是天一觀的道長流礁。 經(jīng)常有香客問我,道長罗丰,這世上最難降的妖魔是什么神帅? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮萌抵,結(jié)果婚禮上找御,老公的妹妹穿的比我還像新娘。我一直安慰自己绍填,他們只是感情好霎桅,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讨永,像睡著了一般滔驶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上住闯,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天瓜浸,我揣著相機(jī)與錄音,去河邊找鬼比原。 笑死插佛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的量窘。 我是一名探鬼主播雇寇,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了锨侯?” 一聲冷哼從身側(cè)響起嫩海,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎囚痴,沒想到半個(gè)月后叁怪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡深滚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年奕谭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痴荐。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡血柳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出生兆,到底是詐尸還是另有隱情难捌,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布鸦难,位于F島的核電站根吁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏明刷。R本人自食惡果不足惜婴栽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一满粗、第九天 我趴在偏房一處隱蔽的房頂上張望辈末。 院中可真熱鬧,春花似錦映皆、人聲如沸挤聘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽组去。三九已至,卻和暖如春步淹,著一層夾襖步出監(jiān)牢的瞬間从隆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國打工缭裆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留键闺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓澈驼,卻偏偏與公主長得像辛燥,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容