第三章--自定義控件

1 dp,sp,px

  • 名詞解釋
  • px:像素碟刺,就是屏幕上的點(diǎn)旱易,如圖片的像素大小為32*32偏瓤,這就是指的像素
  • dpi:每英寸點(diǎn)數(shù)份乒,即每英寸包括的像素個(gè)數(shù)恕汇,用對(duì)角線上像素點(diǎn)數(shù)/對(duì)角線長(zhǎng)度。
  • dp:設(shè)備獨(dú)立像素或辖,與像素密度密切相關(guān)瘾英。在dpi=160的設(shè)備上,1dp=1px.
  • sp:相當(dāng)于dp颂暇,常用于文字修飾
  • dip:=dp
  • 使用
  • 常用尺寸大小dp
  • 文字尺寸用sp
  • 在屏幕上畫(huà)一個(gè)分割線可以用px缺谴,比如1px
  • m,h,xh,xxh,xxxh.1.5倍的等比

2 LayoutInflater

將xml文件解析為視圖

  • 獲得LayoutInflater實(shí)例的三種方法
  • LayoutInflater m1 = getLayoutInflater()
  • LayoutInflater layoutInflater = getSystemService(LATOU_INFLATER_SERVICE)
  • LayoutInflater layoutInflater = LayoutInflater.from(Context)
  • 從源碼來(lái)看,三種方法其實(shí)都是一種耳鸯,就是第二種
    /**
     * Obtains the LayoutInflater from the given context.
     */
    public static LayoutInflater from(Context context) {
        LayoutInflater LayoutInflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (LayoutInflater == null) {
            throw new AssertionError("LayoutInflater not found.");
        }
        return LayoutInflater;
    }

從上面from()的源碼來(lái)看湿蛔,方法里就調(diào)用了getSystemService()膀曾,所以殊途同歸。
tips:getLayoutInflater()還沒(méi)找到

3 提取布局屬性:theme&style

當(dāng)控件的很多屬性有重合的時(shí)候阳啥,可以把它們相同的屬性提取出來(lái)添谊,這樣可以減少代碼的冗余度。

這里寫(xiě)圖片描述

也可用parent繼承已有的style察迟,在代碼中是這樣引用的


這里寫(xiě)圖片描述

4 如何自定義屬性

深入理解android的自定義屬性斩狱,寫(xiě)的更加易懂,以下參考了這篇博客卷拘。

  • 創(chuàng)建屬性
  • value下新建資源文件喊废,命名attrs_+類名
  • <declare-styleable><declare-styleable/>:聲明屬性。這個(gè)標(biāo)簽是必須的嗎栗弟?答案否」す耄可以把這個(gè)去掉乍赫,直接聲明屬性。但是如果沒(méi)有這個(gè)標(biāo)簽陆蟆,有些工作需要我們?nèi)プ隼壮В热纾帉?xiě)常量(屬性的下標(biāo)叠殷,int[]數(shù)組)如改鲫,在R.java中生成的代碼就要我們?nèi)ゾ帉?xiě)
public static final class attr{
    public static final int backgroundColor=0x7f0100b3;
}
public static final class styleable {

    public static final int[] RedTextButton = {
            0x7f0100b3, 0x7f0100b4
        };
    public static final int RedTextButton_backgroundColor = 0;
    public static final int RedTextButton_textSize = 1;
}

所以有了這個(gè)標(biāo)簽,我們就可以只去關(guān)注這些屬性的編寫(xiě)了林束,更加高效像棘。

  • <attr/>name:名稱;format:設(shè)置類型
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RedTextButton">
        <attr name="backgroundColor" format="color"/>
        <attr name="textSize" format="integer"/>
        <attr name="text" format="string"/>
    </declare-styleable>
</resources>
  • 然后在CustomView代碼中獲取這些屬性
    public void init(Context context, AttributeSet attrs){
   
        this.setOnClickListener(this);

        TypedArray typedArray = context.obtainStyledAttributes(
                attrs,R.styleable.RedTextButton);
        mBackGroundColor = typedArray.getColor(
                R.styleable.RedTextButton_backgroundColor, Color.BLUE);
                   mText = typedArray.getString(R.styleable.RedTextButton_text);
        typedArray.recycle();
               //
        mTextSize = typedArray.getInteger(R.styleable.RedTextButton_textSize, 18);
    }

AttributeSet:參數(shù)的集合壶冒,其實(shí)可以通過(guò)getAttributeName()和getAttributeValue()獲得所有屬性的key和value缕题。但是為什么還要使用TypeArray呢?因?yàn)槿绻鹶alue是引用類型如"@string/app_name",那么它獲得的value將是@+一串?dāng)?shù)字胖腾,如果要把這些數(shù)字解析出來(lái)烟零,則還需要寫(xiě)代碼完成這項(xiàng)工作,而TypeArray是簡(jiǎn)化了我們的工作咸作。參考TextView獲取屬性的代碼锨阿,可見(jiàn)系統(tǒng)也是這樣做的

        /*
         * Look the appearance up without checking first if it exists because
         * almost every TextView has one and it greatly simplifies the logic
         * to be able to parse the appearance first and then let specific tags
         * for this View override it.
         */
        TypedArray a = theme.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.TextViewAppearance, defStyleAttr, defStyleRes);
        TypedArray appearance = null;
        int ap = a.getResourceId(
                com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
        a.recycle();
        ....
  • 如果直接使用系統(tǒng)的屬性,則直接在attrs.xml中聲明
<resources>
    <declare-styleable name="RedTextButton">
        <attr name="backgroundColor" format="color"/>
        <attr name="textSize" format="integer"/>
        <attr name="android:text"/>
    </declare-styleable>
</resources>

5 自定義控件的步驟

步驟如下:

  1. 自定義屬性
  2. 在customView中獲取這些屬性
  3. 重寫(xiě)onMesure记罚。老師沒(méi)有說(shuō)墅诡,但是不寫(xiě)好像有一丟丟的問(wèn)題
  4. 重寫(xiě)onDraw。繪制
    既然步驟知道了毫胜,那就開(kāi)始书斜。自定義屬性和獲取屬性上面已經(jīng)介紹一遍了诬辈,接下來(lái)就是重寫(xiě)一系列方法
  • 重寫(xiě)draw方法
      /**
     *
     * @param canvas 繪圖工具
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mPanit.setTextSize(mTextSize);
        //獲取文字四周的矩形,文字荐吉,開(kāi)始的位置焙糟,結(jié)束的位置,把文字的四周邊距計(jì)算出來(lái)放在mRect中
        mPanit.getTextBounds(mText, 0, mText.length(), mRect);

        float textWidth = mRect.width();
        float textHeight = mRect.height();

        mPanit.setColor(mBackGroundColor);
        canvas.drawRect(0f, 0f, getMeasuredWidth(),getMeasuredHeight() ,mPanit);

        //中間一個(gè)白色的數(shù)字
        mPanit.setColor(Color.WHITE);
        canvas.drawText(mText, getWidth() / 2 - textWidth / 2, getHeight() / 2 + textHeight / 2, mPanit);

        mPanit.setColor(Color.YELLOW);
        canvas.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, mPanit);

    }

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <com.example.myactionbardemo.RedTextButton
        android:id="@+id/my"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginLeft="2dp"
        android:layout_marginTop="2dp"
        app:text="10"
        app:backgroundColor="@color/myColor"
        app:textSize="70sp"/>
  
</LinearLayout>

顯示如下


這里寫(xiě)圖片描述

如果把寬高改成wrapcontent,則會(huì)變成(數(shù)字我設(shè)置了點(diǎn)擊事件所以變了)样屠。不符合


這里寫(xiě)圖片描述

所以需要重寫(xiě)onMesure方法
重寫(xiě)之前了解 MeasureSpec 的 specMode穿撮,一共分為三種類型:
EXACTLY:一般表示設(shè)置了 明確值,或者 match_parent 痪欲;
AT_MOST:表示子控件限制在一個(gè)最大值內(nèi)悦穿,一般為 wrap_content;
UNSPECIFIED:表示子控件像多大就多大业踢,很少使用

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;
        int height;

        if (widthMode == MeasureSpec.EXACTLY){
            width = widthSize;
        }else {

            mPanit.setTextSize(mTextSize);
            //獲取文字四周的矩形栗柒,文字,開(kāi)始的位置知举,結(jié)束的位置瞬沦,把文字的四周邊距計(jì)算出來(lái)放在mRecr中
            mPanit.getTextBounds(mText, 0, mText.length(), mRect);
            int desired = getPaddingLeft() + getPaddingRight() + mRect.width();
            width = desired;
        }

        if (heightMode == MeasureSpec.EXACTLY)
        {
            height = heightSize;
        } else
        {

            mPanit.setTextSize(mTextSize);
            //獲取文字四周的矩形,文字雇锡,開(kāi)始的位置逛钻,結(jié)束的位置,把文字的四周邊距計(jì)算出來(lái)放在mRecr中
            mPanit.getTextBounds(mText, 0, mText.length(), mRect);
            int desired = (getPaddingTop()  + getPaddingBottom() + mRect.height());
            height = desired;
        }
       setMeasuredDimension(width, height);
    }

然后wrapcontent就會(huì)變成

這里寫(xiě)圖片描述

但是還有一個(gè)問(wèn)題就是文字看上去不是那么居中锰提,這篇博客關(guān)于文字居中寫(xiě)得特別的詳細(xì)怎么繪制居中文字曙痘,碼著學(xué)習(xí)。
最后給view添加一個(gè)點(diǎn)擊事件立肘,點(diǎn)擊一下數(shù)字會(huì)減少

    @Override
    public void onClick(View view) {

        int mNumber = Integer.parseInt(mText);
        if (mNumber > 0){
            mNumber--;

        }else {
            mNumber = 10;
        }
        mText=String.valueOf(mNumber);
        invalidate();
    }

tips:
自定義控件水太深
我現(xiàn)在有點(diǎn)餓

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末边坤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子赛不,更是在濱河造成了極大的恐慌惩嘉,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踢故,死亡現(xiàn)場(chǎng)離奇詭異文黎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)殿较,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)耸峭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人淋纲,你說(shuō)我怎么就攤上這事劳闹。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵本涕,是天一觀的道長(zhǎng)业汰。 經(jīng)常有香客問(wèn)我,道長(zhǎng)菩颖,這世上最難降的妖魔是什么样漆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮晦闰,結(jié)果婚禮上放祟,老公的妹妹穿的比我還像新娘。我一直安慰自己呻右,他們只是感情好跪妥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著声滥,像睡著了一般眉撵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上落塑,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天执桌,我揣著相機(jī)與錄音,去河邊找鬼芜赌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛伴逸,可吹牛的內(nèi)容都是我干的缠沈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼错蝴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼洲愤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起顷锰,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤柬赐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后官紫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體肛宋,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年束世,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了酝陈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毁涉,死狀恐怖沉帮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤穆壕,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布待牵,位于F島的核電站,受9級(jí)特大地震影響喇勋,放射性物質(zhì)發(fā)生泄漏缨该。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一茄蚯、第九天 我趴在偏房一處隱蔽的房頂上張望压彭。 院中可真熱鬧,春花似錦渗常、人聲如沸壮不。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)询一。三九已至,卻和暖如春癌椿,著一層夾襖步出監(jiān)牢的瞬間健蕊,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工踢俄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缩功,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓都办,卻偏偏與公主長(zhǎng)得像嫡锌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子琳钉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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