007-Android自定义View(2):组合式详解(图文)

222 阅读1分钟

1.简述

顾名思义,即xml文件中根布局使用RelativeLayout(同理其他布局控件), 内部使用其他View控件,布局摆放,组合成XxxView的原始布局。 然后,Java类继承根布局标签对应的容器类,覆写构造函数,并初始化各子View的变量。 是最常用、最稳妥、不易产生过度绘制、内存泄漏等问题。

2. 实践

2.1 编辑 组合View的UI

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/icon_arrow"
        android:layout_width="24dp"
        android:layout_height="30dp"
        android:layout_alignParentEnd="true"
        android:layout_centerVertical="true"
        android:layout_marginTop="3dp"
        android:layout_marginEnd="10dp"
        android:layout_marginBottom="3dp"
        android:src="@drawable/ic_baseline_arrow_forward_ios_24" />
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="6dp"
        android:gravity="center"
        android:lines="1"
        android:maxLines="1"
        android:paddingTop="6dp"
        android:paddingBottom="6dp"
        android:singleLine="true"
        android:text="安全中心"
        android:textColor="#808080"
        android:textSize="14sp" />
</RelativeLayout>

2.2 res/values/attrs.xml 编写快捷属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CommonRowEntranceView">
        <!--  混合类型:颜色int值+引用类型  属性定义时可以指定多种类型值-->
        <attr name="row_bg" format="color|reference" />
        <attr name="row_txt_color" format="color" />
        <!--  String -->
        <attr name="row_txt" format="string" />
    </declare-styleable>
</resources>

2.3 继承根标签布局类,获取属性、设置属性

package com.cupster.base_super_resource;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.RequiresApi;

public class CommonRowEntranceView  extends RelativeLayout {

    public CommonRowEntranceView(Context context) {
        super(context);
        initInnerView(context);
    }

    public CommonRowEntranceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initInnerView(context);
        initAttrs(context, attrs);
    }

    public CommonRowEntranceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initInnerView(context);
        initAttrs(context, attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public CommonRowEntranceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initInnerView(context);
        initAttrs(context, attrs);
    }

    RelativeLayout mRootLayout ;
    TextView mTitle ;
    ImageView mArrow;

    private void initInnerView(Context context) {
        LayoutInflater.from(context).inflate(R.layout.view_common_row_entrance, this, true);//此处应为关联true,否则报错
        mRootLayout = findViewById(R.id.layout_root);
        mArrow = findViewById(R.id.icon_arrow);
        mTitle = findViewById(R.id.title);
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CommonRowEntranceView);
        //取值
        Drawable bgDrawable = typedArray.getDrawable(R.styleable.CommonRowEntranceView_row_bg);
        int txtColor= typedArray.getInt(R.styleable.CommonRowEntranceView_row_txt_color, Color.parseColor("#808080"));
        String title = typedArray.getString(R.styleable.CommonRowEntranceView_row_txt);
        //使用
        if (bgDrawable == null) {
            mRootLayout.setBackgroundColor(Color.WHITE);
        } else {
            mRootLayout.setBackground(bgDrawable);
        }
        if (!TextUtils.isEmpty(title)) {
            mTitle.setText(title);
        }
        mTitle.setTextColor(txtColor);
        //释放资源
        typedArray.recycle();
    }
}

2.4 实际场景使用


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:orientation="vertical"
        >
        <com.cupster.base_super_resource.CommonRowEntranceView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

            app:row_txt="安全中心"
            app:row_txt_color="#404040"
            app:row_bg="#f2f2f2"
            />
        <com.cupster.base_super_resource.CommonRowEntranceView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

            app:row_txt="清理缓存"
            app:row_txt_color="#404040"
            app:row_bg="#f2f2f2"
            />
        <com.cupster.base_super_resource.CommonRowEntranceView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

            app:row_txt="版本检测"
            app:row_txt_color="#404040"
            app:row_bg="#f2f2f2"
            />
        <com.cupster.base_super_resource.CommonRowEntranceView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

            app:row_txt="关于我们"
            app:row_txt_color="#404040"
            app:row_bg="#f2f2f2"
            />
    </LinearLayout>

3. 细节注意

  1. Android的自定义View预览,需要在自定义View编写无误且编译过,才能直接在PreView窗口预览效果
  2. 建议属性名前面加前缀,如:row_xxxxx;规范 & 避免资源命名冲突
  3. 属性值的获取,注意使用对应的TypeArray方法获取,否则会坑了自己。
  4. 属性值对应的获取方法可参考Android自定义View(1):基础