zoukankan      html  css  js  c++  java
  • 如何更好的通过Inflate layout的方式来实现自定义view

    本篇文章讲的是如何用现有控件产生一个组合控件的方法,十分简单实用。现在开始!

    一、需求

    我们要实现一个有红点和文字的按钮控件,就像下面这样:

    二、实现

    我的思路是让一个button和一个textview进行组合。

    <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标签主要是用来避免重复嵌套的。

    接着我在java代码中加载这个xml文件

    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,在布局中因为不知道最外层是什么控件,所以就不能很好的进行预览。预览的问题无法解决,但是我们有方法让控件最外层的属性加回来。

    三、解决merge属性丢失的问题

    有三种办法可以将它们添加回来:

    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

  • 相关阅读:
    兼容性问题
    【浏览器渲染原理】 渲染树和页面渲染
    leetcode153. 寻找旋转排序数组中的最小值
    leetcode162. 寻找峰值
    各种常量池
    leetcode137. 只出现一次的数字 II
    leetcode136. 只出现一次的数字
    leetcode133. 克隆图
    ClassLoader分类
    overload和override
  • 原文地址:https://www.cnblogs.com/tianzhijiexian/p/4632485.html
Copyright © 2011-2022 走看看