通訊錄A-Z指示器Demo

:)

**from** bing 17/**04**/2**9**

本文主要是介紹了一個自定義控件的實現(xiàn)

  • 首先來看demo效果
**Demo**就是這個樣兒 **^_^**
  • 這里有幾個問題需要注意
  • 控件的 高度 怎么確定
  • 字體問題每個字符的 字體 都不一樣
  • 字體 顏色 問題,當(dāng)前選中的字符顏色是不一樣的
  • 怎么判斷當(dāng)前是 選中 的那個字符

選擇實現(xiàn)方案句狼,是繼承View還是ViewGroup

  • 繼承ViewGroup(比如:LinearLayout)嗜浮,好處就是比較方便實現(xiàn)李滴,不是太好的就是效率不高(要實例化多個子控件)
  • 繼承View荧琼,好處就是效率較高,自己比較好控制充甚,不爽的就是比較麻煩演熟。

這個demo就選擇繼承View吧

  • 接下來一個一個解決上面提到的問題(字體鞭执,顏色,高度芒粹,滑動的位置判斷)

總體思路

  • 首先要明白的一點是滑動的監(jiān)聽肯定是通過重寫onTouchEvent方法來實現(xiàn)的兄纺。這里就還有一個問題,onTouchEvent方法我們只能得到坐標(biāo)信息怎么通過坐標(biāo)信息轉(zhuǎn)變成當(dāng)前是滑動到那個字符化漆?demo采用的解決方法是將每個字符對應(yīng)的坐標(biāo)都保存到一個實體里面估脆,判斷位置的時候就根據(jù)每個字符的坐標(biāo)信息就可以判斷是滑動到那個實體。

  • 字體大小怎么確定座云?demo里面規(guī)定了一個最大的字體最小的字體疙赠,當(dāng)前選中的字符使用最大的字體付材,其他字符就根據(jù)它離最大字體的位置來設(shè)置字體大小

  • 控件的高度的確定?其實就是當(dāng)選中中間的字符的時候的高度


下面有大量代碼

                                [↓][↓][↓]
                                [↓][↓][↓]
                                [↓][↓][↓]
                          [↓][↓][↓][↓][↓][↓][↓]
                                [↓][↓][↓]
                                   [↓]

定義控件會用到的屬性

/**
     *
     * 最大的字體
     *
     */
    private int maxTextSize = DEFAULT_MAX_TEXT_SIZE;

    /**
     *
     * 最小的字體
     *
     */
    private int minTextSize = DEFAULT_MIN_TEXT_SIZE;

    /**
     *
     * 不同字體之間的間隔
     *
     */
    private int textSizeStep = DEFAULT_TEXT_STEP;

    /**
     *
     * 選中的時候字體顏色
     *
     */
    private int choiseTextColor = DEFAULT_CHOISE_COLOR;

    /**
     *
     * 默認(rèn)的字體顏色
     *
     */
    private int defaultTextColor = DEFAULT_COLOR;


    /**
     *
     * 字符上下間距
     *
     *
     */
    private int margin = 8;

    private static final int DEFAULT_MAX_TEXT_SIZE = 100;//px
    private static final int DEFAULT_MIN_TEXT_SIZE = 15;
    private static final int DEFAULT_TEXT_STEP = 10;
    private static final int DEFAULT_CHOISE_COLOR = Color.BLACK;
    private static final int DEFAULT_COLOR = Color.GRAY;

    /**
     *
     * 默認(rèn)的選中位置
     *
     *
     */
    private int currentChoise = 0;

建立一個實體類來保存每個字符的位置信息(在滑動和繪制的時候判斷位置)

class TextSizeModel {

        private int x;
        private int y;
        private int textSize;

        private String item;
    }
  • 會為每個字符都生成一個這樣的實體圃阳,實體里面的textSize保存當(dāng)前字符的字體大小厌衔,當(dāng)選中位置改變之后就可以更新這個實體類,最后在繪制的時候根據(jù)這個實體類的信息來進(jìn)行繪制就可以了

控件高度的確定(這個肯定就是重寫 onMeasure了)


 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int width = maxTextSize + margin * 2;
        int height = margin * 2;

        if(datas == null || datas.size() == 0){
            setMeasuredDimension(width,height);
            return;
        }

        currentChoise = datas.size() / 2;
        //height += initItemTextSize();

        for(int i = 0;i < datas.size();i++){
            int duration = i < currentChoise ? currentChoise - i : i - currentChoise;
            int textSize = maxTextSize - duration * textSizeStep;
            textSize = textSize < minTextSize ? minTextSize : textSize;
            datas.get(i).setTextSize(textSize);

            height += textSize + margin;
        }

        setMeasuredDimension(width,height);

    }

  • 這里的datas就是所有字符的實體類

  • currentChoise = datas.size() / 2 這個主要是當(dāng)選中中間位置的時候控件的高度是最高的

  • 高度的計算方法其實也比較簡單捍岳,就是看當(dāng)前字符距離當(dāng)前選中字符的個數(shù)富寿,textSize = 最大的字體 - 當(dāng)前的距離 * 字體偏移量

  • 這里還有一個要注意的是 onMeasure 里面初始化了字體的大小


有了字體大小,接下來就是繪制了(onDraw)

@Override
    protected void onDraw(Canvas canvas) {

        int currentY = margin + maxTextSize;
        for(int i = 0;i < datas.size();i++){
            paint.setColor(i == currentChoise ? choiseTextColor : defaultTextColor);
            paint.setTextSize(datas.get(i).getTextSize());
            canvas.drawText(datas.get(i).getItem(),
                    getMeasuredWidth() / 2,currentY,paint);
            datas.get(i).setX(0);
            datas.get(i).setY(currentY);
            currentY += datas.get(i).getTextSize() + margin;
        }

    }

  • 這里其實就是便利實體類集合锣夹,根據(jù)onMesure里面測量的字體大小就行字符的繪制就可以了
  • 還有一個需要注意的是這里進(jìn)行的實體的坐標(biāo)的設(shè)置

滑動的監(jiān)聽(onTouchEvent)


@Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                for(int i=0;i < datas.size();i++){
                    TextSizeModel model = datas.get(i);
                    if(model.getY() < y && model.getY() + margin > y){
                        currentChoise = i;
                        break;
                    }
                }
                initItemTextSize();
                postInvalidate();
                break;
            case MotionEvent.ACTION_UP:
                break;
        }

        return true;
    }

  • 主要就是在ACTION_MOVE的時候進(jìn)行坐標(biāo)判斷页徐,根據(jù)上一次繪制的時候?qū)嶓w的坐標(biāo)和當(dāng)前坐標(biāo)更新選中的位置,最后initItemTextSize重新根據(jù)當(dāng)前的選中位置更新了每個字符的字體大小银萍,之后繪制

源碼

package com.suse.yuxin.emptydemo.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.suse.yuxin.emptydemo.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2017/4/29.
 */

public class LettersView extends View{

    /**
     *
     * 最大的字體
     *
     */
    private int maxTextSize = DEFAULT_MAX_TEXT_SIZE;

    /**
     *
     * 最小的字體
     *
     */
    private int minTextSize = DEFAULT_MIN_TEXT_SIZE;

    /**
     *
     * 不同字體之間的間隔
     *
     */
    private int textSizeStep = DEFAULT_TEXT_STEP;

    /**
     *
     * 選中的時候字體顏色
     *
     */
    private int choiseTextColor = DEFAULT_CHOISE_COLOR;

    /**
     *
     * 默認(rèn)的字體顏色
     *
     */
    private int defaultTextColor = DEFAULT_COLOR;


    /**
     *
     * 字符上下間距
     *
     *
     */
    private int margin = 8;

    private static final int DEFAULT_MAX_TEXT_SIZE = 100;//px
    private static final int DEFAULT_MIN_TEXT_SIZE = 15;
    private static final int DEFAULT_TEXT_STEP = 10;
    private static final int DEFAULT_CHOISE_COLOR = Color.BLACK;
    private static final int DEFAULT_COLOR = Color.GRAY;

    /**
     *
     * 默認(rèn)的選中位置
     *
     *
     */
    private int currentChoise = 0;

    private Paint paint;
    private List<TextSizeModel> datas = new ArrayList<>();


    private static final String LOG_TAG = "LettersView_TAG";

    public LettersView(Context context) {
        super(context);
        init(context,null);
    }

    public LettersView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public LettersView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }


    private void init(Context context,AttributeSet attrs) {
        if(attrs == null){
            return;
        }
        //init attr
        TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.LettersView);
        maxTextSize = (int) arr.getDimension(R.styleable.LettersView_maxTextSize,DEFAULT_MAX_TEXT_SIZE);
        minTextSize = (int) arr.getDimension(R.styleable.LettersView_minTextSize,DEFAULT_MIN_TEXT_SIZE);
        textSizeStep = (int) arr.getDimension(R.styleable.LettersView_textStep,DEFAULT_TEXT_STEP);
        choiseTextColor = arr.getColor(R.styleable.LettersView_choiseTextColor,DEFAULT_CHOISE_COLOR);
        defaultTextColor = arr.getColor(R.styleable.LettersView_defaultTextColor,DEFAULT_COLOR);
        arr.recycle();

        Log.i(LOG_TAG,"maxT "+maxTextSize+"  minT"+minTextSize+"   step "+textSizeStep);

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTextAlign(Paint.Align.CENTER);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int width = maxTextSize + margin * 2;
        int height = margin * 2;

        if(datas == null || datas.size() == 0){
            setMeasuredDimension(width,height);
            return;
        }

        currentChoise = datas.size() / 2;
        //height += initItemTextSize();

        for(int i = 0;i < datas.size();i++){
            int duration = i < currentChoise ? currentChoise - i : i - currentChoise;
            int textSize = maxTextSize - duration * textSizeStep;
            textSize = textSize < minTextSize ? minTextSize : textSize;
            datas.get(i).setTextSize(textSize);

            height += textSize + margin;
        }

        setMeasuredDimension(width,height);

    }


    private int initItemTextSize(){
        int height = 0;
        for(int i = 0;i < datas.size();i++){
            int duration = i < currentChoise ? currentChoise - i : i - currentChoise;
            int textSize = maxTextSize - duration * textSizeStep;
            textSize = textSize < minTextSize ? minTextSize : textSize;
            datas.get(i).setTextSize(textSize);

            height += textSize + margin;
        }
        return height;
    }

    @Override
    protected void onDraw(Canvas canvas) {

        int currentY = margin + maxTextSize;
        for(int i = 0;i < datas.size();i++){
            paint.setColor(i == currentChoise ? choiseTextColor : defaultTextColor);
            paint.setTextSize(datas.get(i).getTextSize());
            canvas.drawText(datas.get(i).getItem(),
                    getMeasuredWidth() / 2,currentY,paint);
            datas.get(i).setX(0);
            datas.get(i).setY(currentY);
            currentY += datas.get(i).getTextSize() + margin;
        }

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                for(int i=0;i < datas.size();i++){
                    TextSizeModel model = datas.get(i);
                    if(model.getY() < y && model.getY() + margin > y){
                        currentChoise = i;
                        break;
                    }
                }
                initItemTextSize();
                postInvalidate();
                break;
            case MotionEvent.ACTION_UP:
                break;
        }

        return true;
    }



    public void setData(List<String> letters){
        if(letters == null || letters.size() == 0){
            return;
        }
        datas.clear();
        for (String letter : letters) {
            TextSizeModel sizeModel = new TextSizeModel();
            sizeModel.setItem(letter);
            datas.add(sizeModel);
        }
        requestLayout();
    }


    public void setData(String[] letters){
        if(letters == null || letters.length == 0){
            return;
        }
        List<String> l = new ArrayList<>();
        for(int i=0;i < letters.length;i++){
            l.add(letters[i]);
        }
        setData(l);
    }


    class TextSizeModel {

        private int x;
        private int y;
        private int textSize;

        private String item;

        public int getX() {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        public int getY() {
            return y;
        }

        public void setY(int y) {
            this.y = y;
        }

        public int getTextSize() {
            return textSize;
        }

        public void setTextSize(int textSize) {
            this.textSize = textSize;
        }

        public String getItem() {
            return item;
        }

        public void setItem(String item) {
            this.item = item;
        }
    }

}

<declare-styleable name="LettersView">
        <attr name="maxTextSize" format="dimension"/>
        <attr name="minTextSize" format="dimension"/>
        <attr name="choiseTextColor" format="color"/>
        <attr name="defaultTextColor" format="color"/>
        <attr name="textStep" format="color"></attr>
    </declare-styleable>


如何使用


public class LettersTestActivity  extends AppCompatActivity{


    LettersView lettersView;


    String[] letters = new String[]{
            "A","B","C","D","E","F","G",
            "H","I","J","K","L","M","N",
            "O","P","Q","R","S","T","U",
            "V","W","X","Y","Z"
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_letters_test);
        lettersView = (LettersView) findViewById(R.id.activity_letters_test_content);
        lettersView.setData(letters);
    }
}

Nothing is certain in this life. The only thing i know for sure is that. I love you and my life. That is the only thing i know. have a good day

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末泞坦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子砖顷,更是在濱河造成了極大的恐慌捉撮,老刑警劉巖奋救,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘱巾,居然都是意外死亡授嘀,警方通過查閱死者的電腦和手機物咳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹄皱,“玉大人览闰,你說我怎么就攤上這事∠镎郏” “怎么了压鉴?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锻拘。 經(jīng)常有香客問我油吭,道長,這世上最難降的妖魔是什么署拟? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任婉宰,我火速辦了婚禮,結(jié)果婚禮上推穷,老公的妹妹穿的比我還像新娘心包。我一直安慰自己,他們只是感情好馒铃,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布蟹腾。 她就那樣靜靜地躺著痕惋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪岭佳。 梳的紋絲不亂的頭發(fā)上血巍,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機與錄音珊随,去河邊找鬼述寡。 笑死,一個胖子當(dāng)著我的面吹牛叶洞,可吹牛的內(nèi)容都是我干的鲫凶。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼衩辟,長吁一口氣:“原來是場噩夢啊……” “哼螟炫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起艺晴,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤昼钻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后封寞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體然评,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年狈究,在試婚紗的時候發(fā)現(xiàn)自己被綠了碗淌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡抖锥,死狀恐怖亿眠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情磅废,我是刑警寧澤纳像,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站拯勉,受9級特大地震影響爹耗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谜喊,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一潭兽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧斗遏,春花似錦山卦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枚碗。三九已至,卻和暖如春铸本,著一層夾襖步出監(jiān)牢的瞬間肮雨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工箱玷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怨规,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓锡足,卻偏偏與公主長得像波丰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子舶得,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,796評論 25 707
  • ¥開啟¥ 【iAPP實現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程掰烟,因...
    小菜c閱讀 6,367評論 0 17
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件沐批、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,066評論 4 62
  • 每一次與別人交往的機會都非常重要纫骑,如果你能將遇到的對象的相關(guān)情況都詳細(xì)記錄下來,就可以拓展自己的人脈九孩。這樣晨間日記...
    笑飛飛閱讀 179評論 0 3
  • 我想經(jīng)歷了很多先馆,我學(xué)到了不少。該柔軟的時候就柔軟捻撑,該大度的時候就大度,想哭就哭缤底,想笑就笑顾患。但同時,該狠心的時候就狠...
    兔子1235閱讀 478評論 0 0