自定義View系列(三)初始自定義TextView

自定義view车吹,自認(rèn)為不是一步登天,要循序漸進(jìn)较鼓,所以從最簡單的的TextView開始椎木,小試牛刀,對自定義view有一個全面認(rèn)識博烂。

1.創(chuàng)建

繼承自view

public class TextView extends View {
// 構(gòu)造函數(shù)會在代碼里面new的時候調(diào)用
// TextView tv = new TextView(this);
public TextView(Context context) {
    this(context, null);
}
// 在布局layout中使用(調(diào)用)
public TextView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}
// 在布局layout中使用(調(diào)用)香椎,但是會有style
public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

2.自定義屬性

在res-->valus下創(chuàng)建attrs.xml文件

 <!--name 自定義View的名字 TextView-->
<declare-styleable name="TextView">
    <!-- name 屬性名稱
    format 格式: string 文字  color 顏色
                dimension 寬高 字體大小  integer 數(shù)字
                reference 資源(drawable)
     -->
    <attr name="mText" format="string"/>
    <attr name="mTextColor" format="color"/>
    <attr name="mTextSize" format="dimension"/>
    <attr name="mMaxLength" format="integer"/>
    <!-- background 自定義View都是繼承自View , 背景是由View管理的-->
    <!--<attr name="darrenBackground" format="reference|color"/>-->
    <!-- 枚舉 -->
    <attr name="minputType">
        <enum name="number" value="1"/>
        <enum name="text" value="2"/>
        <enum name="password" value="3"/>
    </attr>
</declare-styleable>

在構(gòu)造中獲取屬性 ,并初始化

       private String mText;
       private int mTextSize = 15;
       private int mTextColor = Color.BLACK;

    // 獲取自定義屬性
    TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TextView);

    mText = array.getString(R.styleable.TextView_mText);
    mTextColor = array.getColor(R.styleable.TextView_mTextColor, mTextColor);
    // 15 15px 15sp
    mTextSize = array.getDimensionPixelSize(R.styleable.TextView_mTextSize,sp2px(mTextSize));

    // 回收
    array.recycle();

3.創(chuàng)建畫筆

private Paint mPaint;

在構(gòu)造中創(chuàng)建

    //創(chuàng)建畫筆
    mPaint=new Paint();
    //抗鋸齒
    mPaint.setAntiAlias(true);
    //畫筆大小
    mPaint.setTextSize(mTextSize);
    //畫筆顏色
    mPaint.setColor(mTextColor);

4.測量

  /**
 * 自定義View的測量方法
 * @param widthMeasureSpec
 * @param heightMeasureSpec
 */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    // 布局的寬高都是由這個方法指定
    // 指定控件的寬高禽篱,需要測量
    // 獲取寬高的模式
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    //1.確定的值畜伐,不需要計算
    int width = MeasureSpec.getSize(widthMeasureSpec);

    //2.給的wrap_content 需要計算
    if (widthMode==MeasureSpec.AT_MOST){
        //計算的寬度與字體長度有關(guān) 與字體的大小 用畫筆來測量
       Rect bounds= new Rect();
        mPaint.getTextBounds(mText,0,mText.length(),bounds);
        width=bounds.width()+getPaddingLeft()+getPaddingRight();
    }

    //1.確定的值,不需要計算
    int height = MeasureSpec.getSize(heightMeasureSpec);

    //2.給的wrap_content 需要計算
    if (heightMode==MeasureSpec.AT_MOST){
        //計算的寬度與字體長度有關(guān) 與字體的大小 用畫筆來測量
        Rect bounds= new Rect();
        mPaint.getTextBounds(mText,0,mText.length(),bounds);
        height=  bounds.height()+getPaddingTop()+getPaddingBottom();

    }

   //設(shè)置控件的寬高
    setMeasuredDimension(width,height);
}

5.繪制

/**
 * 用于繪制
 * @param canvas
 */
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //畫文字 text ,x,y,paint
    //求y值基線  bottom是個正值 top是個負(fù)值
    Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
    int dy=(fontMetrics.bottom-fontMetrics.top)/2-fontMetrics.bottom;
    int baseLine=getHeight()/2+dy;
    int x=getPaddingLeft();
    canvas.drawText(mText,x,baseLine,mPaint);
}

6.問題講解

自定義TextView能否繼承LinearLayout,效果能否出來躺率?
答案是可以出來的玛界,但是不會走onDraw()方法
view中得知要中onDraw()方法,有下面代碼

final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&2.               (mAttachInfo     == null || !mAttachInfo.mIgnoreDirtyState);

  if (!dirtyOpaque) onDraw(canvas);

也就是dirtyOpaque為false時會調(diào)用悼吱,mPrivateFlags 到底是怎么賦值的 在View的構(gòu)造函數(shù)中調(diào)用 computeOpaqueFlags

 /**
 * @hide
 */
protected void computeOpaqueFlags() {
    // Opaque if:
    //   - Has a background
    //   - Background is opaque
    //   - Doesn't have scrollbars or scrollbars overlay

    if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) {
        mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND;
    } else {
        mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND;
    }

    final int flags = mViewFlags;
    if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) ||
            (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY ||
            (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) {
        mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS;
    } else {
        mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS;
    }
}

在ViewGroup 中構(gòu)造方法會走 initViewGroup();

  private void initViewGroup() {
    // ViewGroup doesn't draw by default
    if (!debugDraw()) {
        setFlags(WILL_NOT_DRAW, DRAW_MASK);
    }
    mGroupFlags |= FLAG_CLIP_CHILDREN;
    mGroupFlags |= FLAG_CLIP_TO_PADDING;
    mGroupFlags |= FLAG_ANIMATION_DONE;
    mGroupFlags |= FLAG_ANIMATION_CACHE;
    mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;

    if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
        mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
    }

    setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);

    mChildren = new View[ARRAY_INITIAL_CAPACITY];
    mChildrenCount = 0;

    mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
}

其中

   if (!debugDraw()) {
        setFlags(WILL_NOT_DRAW, DRAW_MASK);
    }

導(dǎo)致 mPrivateFlags 會重新賦值

解決思路: 目的就是改變 mPrivateFlags

1.重寫dispatchDraw()慎框,不用重寫onDraw();
2.可以背景透明的背景
3.setWillNotDraw()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市后添,隨后出現(xiàn)的幾起案子笨枯,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猎醇,死亡現(xiàn)場離奇詭異窥突,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)硫嘶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門阻问,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沦疾,你說我怎么就攤上這事称近。” “怎么了哮塞?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵刨秆,是天一觀的道長。 經(jīng)常有香客問我忆畅,道長衡未,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任家凯,我火速辦了婚禮缓醋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绊诲。我一直安慰自己送粱,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布掂之。 她就那樣靜靜地躺著抗俄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪世舰。 梳的紋絲不亂的頭發(fā)上动雹,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機(jī)與錄音跟压,去河邊找鬼洽胶。 笑死,一個胖子當(dāng)著我的面吹牛裆馒,可吹牛的內(nèi)容都是我干的姊氓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼喷好,長吁一口氣:“原來是場噩夢啊……” “哼翔横!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起梗搅,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤禾唁,失蹤者是張志新(化名)和其女友劉穎效览,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荡短,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡丐枉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掘托。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘦锹。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖闪盔,靈堂內(nèi)的尸體忽然破棺而出弯院,到底是詐尸還是另有隱情,我是刑警寧澤泪掀,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布听绳,位于F島的核電站,受9級特大地震影響异赫,放射性物質(zhì)發(fā)生泄漏椅挣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一塔拳、第九天 我趴在偏房一處隱蔽的房頂上張望鼠证。 院中可真熱鬧,春花似錦蝙斜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至攻谁,卻和暖如春稚伍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背戚宦。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工个曙, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人受楼。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓垦搬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親艳汽。 傳聞我的和親對象是個殘疾皇子猴贰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

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