自定义View—ActionBar

876 阅读2分钟

一般的,在一个app中,会有很多的页面,每个页面都会有一个风格统一的标题栏,包含返回键,标题,右标题或图标,输入栏等。这些相同布局如果在每个activity中都写一次,会变得很繁琐。所以要把它封装成一个自定义控件。

看下效果图

可以选择普通标题和输入框模式,有更多需求可以再自行封装进去。

布局代码

<?xml version="1.0" encoding="utf-8"?>
<!--标题-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_head"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/head_back"
        android:layout_width="50dp"
        android:layout_height="match_parent"
        android:gravity="center">

        <ImageView
            android:id="@+id/iv_head_back"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:background="@drawable/icon_back"/>

    </LinearLayout>

    <TextView
        android:id="@+id/head_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toStartOf="@+id/rl_right"
        android:layout_toEndOf="@+id/head_back"
        android:gravity="center"
        android:text="这里是标题"
        android:textColor="#E6000000"
        android:textSize="18sp" />

    <androidx.appcompat.widget.AppCompatEditText
        android:id="@+id/head_et"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toStartOf="@+id/rl_right"
        android:layout_centerVertical="true"
        android:background="@null"
        android:layout_marginHorizontal="10dp"
        android:layout_toEndOf="@+id/head_back"
        android:visibility="gone"/>

    <RelativeLayout
        android:id="@+id/rl_right"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_alignParentEnd="true">

        <ImageView
            android:id="@+id/head_icon_r"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_centerInParent="true"/>

        <TextView
            android:id="@+id/head_title_r"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="#B3000000"
            android:textSize="14sp" />

    </RelativeLayout>

</RelativeLayout>

布局对应的TitleBar类

package com.example.actionbarsizedemo;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatEditText;

/**
 * 自定义头部标题栏
 */
public class TitleBar extends RelativeLayout {

	private static final int DEFAULT = -1;

	private RelativeLayout right;
	private LinearLayout llBack;
	private TextView tvTitle;
	private TextView tvTitleR;
	private ImageView ivBack;
	private ImageView ivRight;
	private AppCompatEditText etTitle;

	private String textTitle;
	private String textRight;
	private String editHint;
	private int titleSize;
	private int colorTitle;
	private int colorRight;
	private boolean isHideBack;
	private int iconBack;
	private int iconRight;
	private int type;

	private OnBackClickListener onBackClickListener;
	private OnTitleRClickListener onTitleRClickListener;

	public TitleBar(@NonNull Context context, @Nullable AttributeSet attrs) {
		super(context, attrs);
		initHeader(context, attrs);
	}

	private void initHeader(Context context, AttributeSet attrs) {
		LayoutInflater.from(context).inflate(R.layout.title_bar, this);
		right = findViewById(R.id.rl_right);
		llBack = findViewById(R.id.head_back);
		tvTitle = findViewById(R.id.head_title);
		tvTitleR = findViewById(R.id.head_title_r);
		ivBack = findViewById(R.id.iv_head_back);
		ivRight = findViewById(R.id.head_icon_r);
		etTitle = findViewById(R.id.head_et);
		onBackClickListener = view -> ((Activity) getContext()).finish();
		llBack.setOnClickListener(view ->
				onBackClickListener.onBackClickListener(view));
		right.setOnClickListener(view -> {
			if (onTitleRClickListener != null)
				onTitleRClickListener.onTitleRClickListener(view);
		});
		TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TitleBar);
		colorTitle = ta.getColor(R.styleable.TitleBar_titleColor, Color.BLACK);
		colorRight = ta.getColor(R.styleable.TitleBar_subheadingColor, Color.BLACK);
		textTitle = ta.getString(R.styleable.TitleBar_titleText);
		editHint = ta.getString(R.styleable.TitleBar_editHint);
		textRight = ta.getString(R.styleable.TitleBar_subheadingText);
		isHideBack = ta.getBoolean(R.styleable.TitleBar_isHideBack, false);
		iconBack = ta.getResourceId(R.styleable.TitleBar_backIconSrc, DEFAULT);
		iconRight = ta.getResourceId(R.styleable.TitleBar_rightIconSrc, DEFAULT);
		type = ta.getInt(R.styleable.TitleBar_type, 0);
		ta.recycle();
		tvTitle.setText(textTitle);
		tvTitle.setTextColor(colorTitle);
		tvTitleR.setText(textRight);
		tvTitleR.setTextColor(colorRight);
		etTitle.setHint(editHint);
		if (iconBack != DEFAULT)
			ivBack.setBackgroundResource(iconBack);
		if (iconRight != DEFAULT)
			ivRight.setBackgroundResource(iconRight);
		if (isHideBack)
			llBack.setVisibility(INVISIBLE);
		if (type == 1) {
			tvTitle.setVisibility(GONE);
			etTitle.setVisibility(VISIBLE);
		}
	}

	public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
		this.onBackClickListener = onBackClickListener;
	}

	public void setOnTitleRClickListener(OnTitleRClickListener onTitleRClickListener) {
		this.onTitleRClickListener = onTitleRClickListener;
	}

	public void setTitle(String title) {
		tvTitle.setText(title);
	}

	public void setTitle(int id) {
		tvTitle.setText(id);
	}

	public void setTitleR(String titleR) {
		tvTitleR.setText(titleR);
	}

	public void setTitleR(int id) {
		tvTitleR.setText(id);
	}

	public interface OnTitleRClickListener {
		void onTitleRClickListener(View view);
	}

	public interface OnBackClickListener {
		void onBackClickListener(View view);
	}

}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 自定义标题栏 -->
    <declare-styleable name="TitleBar">
        <!-- 标题文字 -->
        <attr name="titleText" format="string" />
        <!-- 标题颜色 -->
        <attr name="titleColor" format="color" />
        <!-- 标题大小 -->
        <attr name="titleSize" format="dimension" />
        <!-- 右标题颜色 -->
        <attr name="subheadingColor" format="color" />
        <!-- 右标题文字 -->
        <attr name="subheadingText" format="string" />
        <!-- 是否显示隐藏按钮 -->
        <attr name="isHideBack" format="boolean" />
        <!-- 返回按钮的图标 -->
        <attr name="backIconSrc" format="reference" />
        <!-- 右按钮的图标 -->
        <attr name="rightIconSrc" format="reference" />
        <!-- 标题栏类型,标题/输入框-->
        <attr name="type">
            <enum name="title" value="0" />
            <enum name="input" value="1" />
        </attr>
        <!-- 输入框hint-->
        <attr name="editHint" format="string"/>
    </declare-styleable>
</resources>

如何在布局中使用它。

<?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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.example.actionbarsizedemo.TitleBar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:titleText="这里放标题" />

    <com.example.actionbarsizedemo.TitleBar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_marginTop="5dp"
        android:background="#000000"
        app:backIconSrc="@drawable/icon_back_white"
        app:subheadingColor="#CDDC39"
        app:subheadingText="副标题"
        app:titleColor="#fff"
        app:titleText="副标题" />

    <com.example.actionbarsizedemo.TitleBar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_marginTop="10dp"
        android:background="#8BC34A"
        app:isHideBack="true"
        app:titleText="隐藏返回键" />

    <com.example.actionbarsizedemo.TitleBar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_marginTop="10dp"
        android:background="#009688"
        app:rightIconSrc="@drawable/icon_more"
        app:titleColor="#fff"
        app:titleText="显示右图标" />

    <com.example.actionbarsizedemo.TitleBar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_marginTop="10dp"
        android:background="#FFFFFF"
        app:titleColor="#fff"
        app:type="input"
        app:editHint="请输入关键字"/>

</LinearLayout>

在Activity中设置点击事件等

public class MainActivity extends AppCompatActivity {

	private TitleBar tb1;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		tb1 = findViewById(R.id.tb_1);

		tb1.setTitle("代码中设置标题文字");

		tb1.setOnTitleRClickListener(view -> {
			Toast.makeText(this, "点击了右标题", Toast.LENGTH_SHORT).show();
		});

	}
}

代码中有使用lambda表达式,需要在gradle中进行相关配置

compileOptions {
    sourceCompatibility 1.8
    targetCompatibility 1.8
}

目前最新版本的as(4.1)创建项目会自带此配置