Simple implementation of Android custom controls

beginning

foreword

I recently resigned from a small company and decided to review what I have learned before. So publish an article on custom controls to deepen your impression, and at the same time prepare for finding a job in the future. Without further ado, let's start now.

Introduction to Custom Controls

In the development of custom controls in Android, all controls in Android inherit the View class. The following picture is the inheritance relationship diagram of each control.
Inheritance Diagram
In fact, the so-called custom control actually inherits the View class and rewrites the internal methods inside. Generally speaking, there are three ways to customize controls:
1. Customize View: Inherit View.
2. Based on existing components: Inherit the derived class of View.
3. The way of combination: the custom control contains other components.

Today, we will introduce the combination method to realize the custom View. The other two methods will be published after the editor learns.

practice

No matter how much theory is said, it is not as real as practice. Here is a design drawing downloaded from the Internet.

DEMO diagram

analyze

If we want to implement this kind of interface, it seems to be quite simple, and there is no need to customize it, but compared to some people who want to be lazy (for the sake of long-term development). It's better to customize it, so that when we need to use it in other layout files, it can be used directly as a control. Is it convenient? ?
In fact, to put it bluntly, it is to customize the following picture as a control, and use it directly as a control when it is used later.

insert image description here

The idea of ​​implementation is actually quite simple. Customize a combined View, wrap it horizontally in a linear layout, and arrange ImageView, TextView, TextView, and ImageView in sequence. Not much nonsense, let's see how to achieve it.

accomplish

1. Define custom control layout (custom_item_view)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

<!--   线性布局水平对齐包裹-->
    <LinearLayout
        android:id="@+id/setting_item"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#ffffff"
        android:padding="5dp"
        android:orientation="horizontal">

        <!--   自定义控件中第一个图片-->
        <ImageView
            android:id="@+id/setting_item_logo"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"/>
        <!--   自定义控件中标题-->
        <TextView
            android:id="@+id/setting_item_title"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="5dp"
            android:gravity="center"
            android:textColor="#000000"
            android:textSize="18sp"/>
        <!--   为了实现,用一个TextView将后边的控件显示在右边
                 也可以用RelativeLayout实现-->
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"/>
        <!--   自定义控件中概述-->
        <TextView
            android:id="@+id/setting_item_desc"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginRight="5dp"
            android:gravity="center"
            android:textColor="#999999"
            android:textSize="15sp"/>
        <!--   自定义控件中第二个图片-->
        <ImageView
            android:id="@+id/setting_item_more"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"/>
    </LinearLayout>
    <!--   自定义控件中下划线-->
    <View
        android:id="@+id/setting_item_line"
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:background="#888888"/>
</LinearLayout>
2. Create a new attrs.XML file to set custom control properties
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomSettingItemView">
<!--        Item标题-->
        <attr name="settingItemTitle" format="string"/>
<!--        Item描述-->
        <attr name="settingItemDesc" format="string"/>
<!--        第一张图片-->
        <attr name="settingLogoSrc" format="reference"/>
<!--        第二张图片-->
        <attr name="settingMoreSrc" format="reference"/>
<!--        下划线显示与否-->
        <attr name="settingItemUnderLineVisibility" format="boolean"/>
    </declare-styleable>
</resources>
3. Inherit FrameLayout and override the constructor

Read the attribute parameters in the layout file (see the init method):
If a custom parameter is passed in the layout, it can be read from the AttributeSet in the constructor and set to the control.

package com.example.customview_setting_item.customView;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.example.customview_setting_item.R;

/**
 * Create by 25497 on 2019/10/6
 * The project name is CustomView-setting_item
 * Leo Mark
 *
 * Desc:  自定义控件(继承FrameLayout)
 **/
public class CustomSettingItemView extends FrameLayout {
    
    

    private Context mContext;
    private View mainView;

    private LinearLayout settingItem;
    private ImageView settingItemLogo;//第一张图片
    private ImageView settingItemMore;//第二张图片
    private TextView settingItemTitle;//标题
    private TextView settingItemDesc;//概述
    private View settingItemUnderLine;//下划线

    private String settingItemTitleText;//标题内容
    private String settingItemDescText;//概述内容
    private int settingItemLogoSrc;//第一张图片路径
    private int settingItemMoreSrc;//第二张图片路径
    private boolean settingItemLineVisibility;//下划线显示与否判断

    public String getSettingItemTitleText() {
    
    
        return settingItemTitleText;
    }

    public void setSettingItemTitleText(String settingItemTitleText) {
    
    
        if (settingItemTitleText!=null){
    
    
            this.settingItemTitleText = settingItemTitleText;
            settingItemTitle.setText(settingItemTitleText);//将内容设置进控件中
        }

    }

    public String getSettingItemDescText() {
    
    
        return settingItemDescText;
    }

    public void setSettingItemDescText(String settingItemDescText) {
    
    
        if (settingItemDescText!=null) {
    
    
            this.settingItemDescText = settingItemDescText;
            settingItemDesc.setText(settingItemDescText);//将内容设置进控件中
        }
    }

    public int getSettingItemLogoSrc() {
    
    
        return settingItemLogoSrc;
    }

    public void setSettingItemLogoSrc(int settingItemLogoSrc) {
    
    
        if (settingItemLogoSrc!=10000) {
    
    
            this.settingItemLogoSrc = settingItemLogoSrc;
            settingItemLogo.setImageResource(settingItemLogoSrc);//将图片地址设置进控件中
        }
    }

    public int getSettingItemMoreSrc() {
    
    
        return settingItemMoreSrc;
    }

    public void setSettingItemMoreSrc(int settingItemMoreSrc) {
    
    
        if (settingItemMoreSrc!=10000) {
    
    
            this.settingItemMoreSrc = settingItemMoreSrc;
            settingItemMore.setImageResource(settingItemMoreSrc);//将图片地址设置进控件中
        }
    }

    public boolean getSettingItemLineVisibility() {
    
    
        return settingItemLineVisibility;
    }

    public void setSettingItemLineSize(boolean settingItemLineVisibility) {
    
    
            this.settingItemLineVisibility = settingItemLineVisibility;
            //判断是否显示下划线
            if (settingItemLineVisibility){
    
    
                settingItemUnderLine.setVisibility(VISIBLE);
            }else{
    
    
                settingItemUnderLine.setVisibility(INVISIBLE);
            }
    }

    public CustomSettingItemView(@NonNull Context context) {
    
    
        super(context);
    }

    public CustomSettingItemView(@NonNull Context context, @Nullable AttributeSet attrs) {
    
    
        super(context, attrs);
        init(context,attrs);
    }

    public CustomSettingItemView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    
    
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    public CustomSettingItemView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    
    
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context,attrs);
    }

    /**
     * 定义自定义控件中的属性
     * @param context
     * @param attrs
     */
    private void init(Context context, AttributeSet attrs) {
    
    
        this.mContext=context;
        LayoutInflater inflater= (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mainView=inflater.inflate(R.layout.custom_setting_item_view,this,true);
        initView(mainView);//初始布局中的控件

        TypedArray typedArray=mContext.obtainStyledAttributes(attrs, R.styleable.CustomSettingItemView);
        setSettingItemTitleText(typedArray.getString(R.styleable.CustomSettingItemView_settingItemTitle));
        setSettingItemDescText(typedArray.getString(R.styleable.CustomSettingItemView_settingItemDesc));
        setSettingItemLogoSrc(typedArray.getResourceId(R.styleable.CustomSettingItemView_settingLogoSrc,10000));
        setSettingItemMoreSrc(typedArray.getResourceId(R.styleable.CustomSettingItemView_settingMoreSrc,10000));
        setSettingItemLineSize(typedArray.getBoolean(R.styleable.CustomSettingItemView_settingItemUnderLineVisibility,true));
    }

    /**
     * 初始化控件
     * @param mainView
     */
    private void initView(View mainView) {
    
    
        settingItemTitle=mainView.findViewById(R.id.setting_item_title);
        settingItemDesc=mainView.findViewById(R.id.setting_item_desc);
        settingItemLogo=mainView.findViewById(R.id.setting_item_logo);
        settingItemMore=mainView.findViewById(R.id.setting_item_more);
        settingItemUnderLine=mainView.findViewById(R.id.setting_item_line);
    }
}

4. Modify the main function layout file

Create the main function entry MainActivity, and in the layout file, just use the customized one as a control, or set it dynamically in the code. I just randomly found the pictures I used before to show it.

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="测试标题1"
        app:settingItemDesc="测试详情1"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="测试标题2"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="测试标题3"
        app:settingItemDesc="测试详情3"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="测试标题4"
        app:settingItemDesc="测试详情4"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"
        app:settingItemUnderLineVisibility="false"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        app:settingItemTitle="测试标题5"
        app:settingItemDesc="测试详情5"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="测试标题6"
        app:settingItemDesc="测试详情6"
        app:settingLogoSrc="@mipmap/soufa"/>
    <com.example.customview_setting_item.customView.CustomSettingItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:settingItemTitle="测试标题7"
        app:settingItemDesc="测试详情7"
        app:settingLogoSrc="@mipmap/soufa"
        app:settingMoreSrc="@mipmap/more"/>

</LinearLayout>
Rendering after running on a virtual machine

Realize the picture

Summarize

The above is the combined implementation of custom controls. In actual development, it is definitely not that simple, but it is inseparable. As long as we understand the way of thinking, we don’t need to care about the unreasonable needs of the project manager. Of course, this is just a simple implementation, if you want to achieve more effects. It can be realized by inheriting the View and rewriting the onMeasure, onLayout, and onDraw of the component through the first custom View written earlier.

Well, one of the ways to customize View is like this. If there are mistakes, I look forward to your criticism and correction. The code word is not easy, I hope you will bookmark, repost, and like it.

Guess you like

Origin blog.csdn.net/weixin_43683367/article/details/102332683