android自定義View之3D索引效果

QQ圖片20161211090532.png

效果圖:
這里寫圖片描述

我的小霸王太卡了湖笨。

最近工作比較忙黄刚,今天搞了一下午才搞出來這個效果黔漂,這種效果有很多種實現方式诫尽,最常見的應該是用貝塞爾曲線實現的。今天我們來看另一種不同的實現方式炬守,只需要用到 canvas.scale()箱锐,有沒有很好奇是怎么實現的呢。

首先來說一下思路劳较,只要有了思路剩下的就是往里面套代碼了。
通過觀察上面的效果圖我們發(fā)現可以把右邊的字母分為三種類型
1浩聋、 手指沒觸摸的地方顯示正常的樣式
2观蜗、手指觸摸的位置 顯示最大且完全不透明
3、手指觸摸位置的上下附近位置 有放大且有透明度變化

對這個效果有了直觀的認識后衣洁,我們就可以在ondraw里面根據不同的條件來分別畫出這三種狀態(tài)墓捻,這里主要難理解的就是這些條件。這需要結合代碼看下。

so 我們開始擼碼吧砖第,

1撤卢、先初始化一些需要的變量


private void init(Context context) {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.GRAY);
        mLetters = context.getResources().getStringArray(R.array.letter_list);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mDensity  = getContext().getResources().getDisplayMetrics().density;
        setPadding(0,dip2px(20),0,dip2px(20));
    }

 private int dip2px(int dipPx){
        return (int)(dipPx*mDensity+0.5);
    }

相信上面這些應該沒什么難度吧。 另外把一些需要的寬高屬性賦值一下梧兼,因為下面會用到它們

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mHeight = h - getPaddingTop() - getPaddingBottom();
        mWidth = w - dip2px(16);
        mLetterHeight = mHeight / mLetters.length;
        int textSize = (int)(mLetterHeight*0.7);
        mPaint.setTextSize(textSize);
        mIsDownRect.set(w-dip2px(32),0,w,h);
    }

這里主要就是mIsDownRect這個要注意一下它是索引列表的范圍放吩,但是我們并不需要畫出它。
2羽杰、在ontouch方法中對觸摸事件進行必要的處理

public boolean onTouchEvent(MotionEvent event) {
       int action = event.getAction();
        switch (action){
            case MotionEvent.ACTION_DOWN:
                mIsBeingDragger = false;
                float initDownY = event.getY();
                if(!mIsDownRect.contains(event.getX(),event.getY())){
                    return false;
                }
                mInitDownY = initDownY;
                break;
            case MotionEvent.ACTION_MOVE:
                float y = event.getY();
                float diff = Math.abs(y - mInitDownY);
                if(diff>mTouchSlop&&!mIsBeingDragger){
                    mIsBeingDragger = true;
                }
                if(mIsBeingDragger){
                    mY = y;
                    float moveY = y - getPaddingTop();
                    int chartIndex = (int) (moveY / mHeight * mLetters.length);//獲取索引位置的index
                    if(mChoose!=chartIndex){
                        if(chartIndex>=0&&chartIndex<mLetters.length) {
                            if (slidViewListener != null) {
                                Log.i("lly","chartIndex = "+chartIndex);
                                slidViewListener.onChange(mLetters[chartIndex]);
                            }
                            mChoose = chartIndex;
                        }
                    }
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mIsBeingDragger = false;
                mChoose = -1;
                invalidate();
                break;
        }

        return true;
    }

這里面也很簡單渡紫,首先當手指按下時記錄下按下位置的Y坐標,然后判斷按下的位置是否在索引列表的區(qū)域范圍內(索引的區(qū)域在初始化賦值的時候已經確定過了)如果不在就沒必要執(zhí)行下去了 直接返回false即可考赛, 然后在手指移動的時候判斷下是否是在移動是的話就把mIsBeingDragger置為true惕澎,如果mIsBeingDragger為true說明正在移動 ,這時候就計算出當前手指所在的索引位置颜骤,并通過回調方式通知外面當前的位置唧喉,最后把索引位置賦給全局變量mChoose,并刷新UI忍抽。 手指抬起時進行一些復位操作八孝。 以上就是ontouch的全部方法。
3梯找、在ondraw方法里面畫出索引字母

這里要畫出那三種類型的字母索引唆阿,我們先從簡單的來

  float lettersPos= mLetterHeight*(i+1)+getPaddingTop(); //下一個字母的Y值坐標
            float diffY; // Y 方向的偏移量
            float diffX;//X 方向的偏移量
            float diff;//縮放比例
  if (mChoose == i&&i!=0&&i!=mLetters.length-1) {
      diff = 2.2f;
      diffX=0f;
      diffY=0f;
  }

mChoose 是在ontouch中我們記錄的索引位置,當上面條件成立時說明當前就是選中的字母锈锤,這時候讓它縮放比例最大驯鳖,偏移量我們會在下面統(tǒng)一處理。 接下來處理不是選中的情況

float distanseDiff = Math.abs((mY - lettersPos)/mHeight);//計算手指觸摸位置的上下附近位置
                float maxPos = distanseDiff * 7;//乘7是因為這個系數太小了需要給他一個放大
                if(distanseDiff<0.174){
                    diff = 2.2f - maxPos;
                }else {
                    diff = 1f;
                }

                if(!mIsBeingDragger){
                    diff =1;
                }
                diffX  = maxPos *  50;
                if(mY>lettersPos){
                    diffY = maxPos*50;
                }else {
                    diffY = - maxPos*50;
                }

這里主要就是那個縮放系數比較難算 需要多試下久免。 X Y方向的偏移量如下圖
這里寫圖片描述

這些都計算好后就可以畫了

 canvas.save();
            canvas.scale(diff,diff,mWidth*1.2f+diffX,lettersPos+diffY);
            if(diff ==1){
                mPaint.setAlpha(255);
                mPaint.setTypeface(Typeface.DEFAULT);

            }else {
                int alpha = (int) (255*(1-Math.min(0.9,diff -1)));
                if(mChoose == i){
                    alpha = 255;

                }
                mPaint.setAlpha(alpha);
                mPaint.setTypeface(Typeface.DEFAULT_BOLD);
            }

可以發(fā)現canvas.scale(diff,diff,mWidth*1.2f+diffX,lettersPos+diffY); 這一句才是整個自定義view的關鍵 它前兩個參數是x軸和y軸的縮放系數浅辙,后兩個參數是x軸和y軸的錨點,我主要是試出來的,這兩個參數比較難理解,還需要多家學習阎姥。到這里就已經實現了我們最上面的效果了记舆。

家里沒有github的環(huán)境所以只傳CSDN了。

源碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末呼巴,一起剝皮案震驚了整個濱河市泽腮,隨后出現的幾起案子,更是在濱河造成了極大的恐慌衣赶,老刑警劉巖诊赊,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異府瞄,居然都是意外死亡碧磅,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲸郊,“玉大人丰榴,你說我怎么就攤上這事「汛椋” “怎么了四濒?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長像吻。 經常有香客問我峻黍,道長,這世上最難降的妖魔是什么拨匆? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任姆涩,我火速辦了婚禮,結果婚禮上惭每,老公的妹妹穿的比我還像新娘骨饿。我一直安慰自己,他們只是感情好台腥,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布宏赘。 她就那樣靜靜地躺著,像睡著了一般黎侈。 火紅的嫁衣襯著肌膚如雪察署。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天峻汉,我揣著相機與錄音贴汪,去河邊找鬼。 笑死休吠,一個胖子當著我的面吹牛扳埂,可吹牛的內容都是我干的。 我是一名探鬼主播瘤礁,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼阳懂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了柜思?” 一聲冷哼從身側響起岩调,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赡盘,沒想到半個月后誊辉,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡亡脑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霉咨。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡蛙紫,死狀恐怖,靈堂內的尸體忽然破棺而出途戒,到底是詐尸還是另有隱情坑傅,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布喷斋,位于F島的核電站唁毒,受9級特大地震影響,放射性物質發(fā)生泄漏星爪。R本人自食惡果不足惜浆西,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望顽腾。 院中可真熱鬧近零,春花似錦、人聲如沸抄肖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漓摩。三九已至裙士,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間管毙,已是汗流浹背腿椎。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锅风,地道東北人酥诽。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像皱埠,于是被迫代替她去往敵國和親肮帐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容