如何更好的經過Inflate layout的方式來實現自定義view

本篇文章講的是如何用現有控件產生一個組合控件的方法,十分簡單實用。如今開始!java

1、需求android

咱們要實現一個有紅點和文字的按鈕控件,就像下面這樣:app

2、實現佈局

個人思路是讓一個button和一個textview進行組合。this

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    >
 
    <RadioButton
        android:id="@+id/tab_btn"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:button="@null"
        android:drawablePadding="1dp"
        android:gravity="center"
        android:textSize="11sp"
        />

    <TextView
        android:id="@+id/tab_hint"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:paddingLeft="4dp"
        android:paddingRight="4dp"
        android:layout_toRightOf="@+id/tab_btn"
        android:layout_marginLeft="-5dp"
        android:textSize="11sp"
        android:minHeight="6dp"
        android:singleLine="true"
        
        />

</merge>

能夠看到最外層我用了merge標籤,這是由於我須要把這個xml加載到一個自定義的RelativeLayout中。merge標籤主要是用來避免重複嵌套的。
spa

接着我在java代碼中加載這個xml文件code

public class BottomTab extends RelativeLayout implements BottomTabImpl {

    public BottomTab(Context context) {
        this(context, null);
    }

    public BottomTab(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BottomTab(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initViews();
    }private void initViews() {
        inflate(getContext(), R.layout.test_xml, this);

這樣就完成了一個初步的自定義view,但咱們要知道merge標籤是有弊端的。<merge>標籤能夠融合其內容,可是不包括自身,所以頂層的屬性都丟失了。並且用了merge,在佈局中由於不知道最外層是什麼控件,因此就不能很好的進行預覽。預覽的問題沒法解決,可是咱們有方法讓控件最外層的屬性加回來。orm

3、解決merge屬性丟失的問題xml

有三種辦法能夠將它們添加回來:blog

1)在代碼中添加

private void initViews() {
        inflate(getContext(), R.layout.card, this);
        // add bg to root view
        setBackgroundColor(getResources().getColor(R.color.card_background));
 
        //Add missing top level attributes    
        int padding = (int)getResources().getDimension(R.dimen.card_padding);
        setPadding(padding, padding, padding, padding);
 
       ……
    }

2)在控件被使用的時候添加丟失的屬性

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <com.trickyandroid.customview.app.view.Card
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

android:background="@color/card_background" android:padding="@dimen/card_padding"

/> </FrameLayout>
3)定義一個stylable 屬性將這些值經過style提供給控件
attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Card">
        <attr name="cardStyle" format="reference"/>
    </declare-styleable>
</resources>
style.xml
  <!-- Base application theme. -->
    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <item name="android:windowBackground">@color/main_background</item>
        <item name="cardStyle">@style/CardStyle</item>
    </style>
 
    <style name="CardStyle" parent="android:Widget.Holo.Light">
        <item name="android:padding">@dimen/card_padding</item>
        <item name="android:background">@color/card_background</item>
    </style>
 
</resources>
Card.java
public class Card extends RelativeLayout {

 
    public Card(Context context) {
        super(context, null, R.attr.cardStyle);
        init();
    }
 
    public Card(Context context, AttributeSet attrs) {
        super(context, attrs, R.attr.cardStyle);
        init();
    }
    .....
須要注意的是要在view的構造方法中要傳入R.attr.xxx的文件,讓控件去調用。爲了更加說明這點,我舉個toolbar的例子來講明。
首先,toolbar在系統中定義了這樣一個attr:
<declare-styleable name="Toolbar">
        <attr name="titleTextAppearance" format="reference" />
        <attr name="subtitleTextAppearance" format="reference" />
        <attr name="title" />
        <attr name="subtitle" />
        <attr name="android:gravity" />
        <attr name="titleMargins" format="dimension" />
        <attr name="titleMarginStart" format="dimension" />
        <attr name="titleMarginEnd" format="dimension" />
        <attr name="titleMarginTop" format="dimension" />
        <attr name="titleMarginBottom" format="dimension" />
        <attr name="contentInsetStart" />
        <attr name="contentInsetEnd" />
        <attr name="contentInsetLeft" />
        <attr name="contentInsetRight" />
        <attr name="maxButtonHeight" format="dimension" />
        <attr name="collapseIcon" format="reference" />
        <attr name="collapseContentDescription" format="string" />
        <attr name="popupTheme" />
        <attr name="navigationIcon" format="reference" />
        <attr name="navigationContentDescription" format="string" />
        <attr name="android:minHeight" />
    </declare-styleable>

而後在代碼中進行了以下的設置:

public Toolbar(Context context) {
        this(context, null);
    }

    public Toolbar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, R.attr.toolbarStyle);
    }

    public Toolbar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        // Need to use getContext() here so that we use the themed context
        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
                R.styleable.Toolbar, defStyleAttr, 0);

        mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
        mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
        mGravity = a.getInteger(R.styleable.Toolbar_android_gravity, mGravity);
        mButtonGravity = Gravity.TOP;
        mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom =
                a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargins, 0);

這樣咱們就知道這個view用到了R.attr.toolbarStyle的屬性,因此若是咱們想要設置一個全局的屬性,那麼能夠在theme中進行設置便可。

 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->

<item name="toolbarStyle">@style/ToolbarStyle</item> <!--<item name="R.attr.actionOverflowMenuStyle" />--> </style>

設置具體的值:

<style name="ToolbarStyle" parent="Base.Widget.AppCompat.Toolbar">
        <item name="titleTextAppearance">@style/TextAppearance.Widget.AppCompat.Toolbar.Title</item>
        <item name="subtitleTextAppearance">@style/TextAppearance.Widget.AppCompat.Toolbar.Subtitle</item>
        <item name="android:minHeight">?attr/actionBarSize</item>
        <item name="titleMargins">0dp</item>
        <item name="maxButtonHeight">56dp</item>
        <item name="collapseIcon">?attr/homeAsUpIndicator</item>
        <item name="collapseContentDescription">@string/abc_toolbar_collapse_description</item>
        <item name="contentInsetStart">0dp</item>
        <item name="android:minWidth">20dp</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">?attr/actionBarSize</item>
    </style>

 

參考自:http://www.devtf.cn/?p=422

相關文章
相關標籤/搜索