将幾個基本控件放在一個布局中并用一個自定義View管理,這樣的控件被稱為”複合自定義控件“。在開發中最常用的複合控件就是界面上的标題欄了,使用率相當高,但制作的難度倒也不大,網上關于自定義标題欄的控件已經一大把了。是以我也為湊個數,把我若幹年前的自定義标題欄拿出來充充數。
首先我們需要定義一個布局檔案:title_bar_layout.xml
布局結構相當簡單,左和右各有一個線形布局用于實作一個圖示按鈕的效果,中間是一個文字控件,用于顯示标題文字。
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" tools:background="@color/colorPrimary"> <LinearLayout android:id="@+id/layoutLeft" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_alignParentBottom="true" android:background="?android:attr/selectableItemBackground" android:orientation="horizontal" android:paddingStart="8dp" android:paddingEnd="8dp"> <ImageView android:id="@+id/ivLeft" android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingEnd="8dp" tools:src="@android:drawable/btn_star" /> <TextView android:id="@+id/tvLeft" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:textColor="@android:color/white" android:textSize="14sp" tools:text="按鈕" /> LinearLayout> <LinearLayout android:id="@+id/layoutRight" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentTop="true" android:layout_alignParentEnd="true" android:layout_alignParentBottom="true" android:background="?android:attr/selectableItemBackground" android:orientation="horizontal" android:paddingStart="8dp" android:paddingEnd="8dp"> <TextView android:id="@+id/tvRight" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:textColor="@android:color/white" android:textSize="14sp" tools:text="按鈕" /> <ImageView android:id="@+id/ivRight" android:layout_width="wrap_content" android:layout_height="match_parent" android:padding="8dp" android:scaleType="centerInside" tools:src="@android:drawable/btn_dialog" /> LinearLayout> <TextView android:id="@+id/tvTitle" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_centerInParent="true" android:background="@android:color/transparent" android:ellipsize="end" android:gravity="center" android:lines="1" android:textSize="18sp" tools:text="Title Text" />RelativeLayout>
然後為控件定義資源檔案:title_bar_styleable.xml(檔案放在values目錄下)
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="TitleBar"> <attr name="text_color" format="color" /> <attr name="bg_color" format="color" /> <attr name="title_text" format="string" /> <attr name="left_text" format="string" /> <attr name="left_image" format="reference" /> <attr name="right_image" format="reference" /> <attr name="right_text" format="string" /> declare-styleable>resources>
接着就開始寫自定義類了:TitleBar.java
package com.example.customerview;import android.content.Context;import android.content.res.TypedArray;import android.text.TextUtils;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;import androidx.core.content.ContextCompat;/** * 自定義标題欄(左右各一個圖檔按鈕,正中文本控件) * 可自定義标題文字,左右圖檔的資源和标題欄的背景色 */public class TitleBar extends RelativeLayout { private ViewGroup vgLeft; private ImageView ivIconLeft; private TextView tvLeft; private ViewGroup vgRight; private ImageView ivIconRight; private TextView tvRight; private TextView tvTitle; private int barBgColor; private int textColor; private String titleString; private String leftText; private String rightText; private int srcLeftImageId = 0; private int srcRightImageId = 0; public TitleBar(Context context) { super(context); initView(context); } public TitleBar(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TitleBar); barBgColor = typedArray.getColor(R.styleable.TitleBar_bg_color, ContextCompat.getColor(context, R.color.colorPrimary)); textColor = typedArray.getColor(R.styleable.TitleBar_text_color, ContextCompat.getColor(context, android.R.color.white)); titleString = typedArray.getString(R.styleable.TitleBar_title_text); leftText = typedArray.getString(R.styleable.TitleBar_left_text); rightText = typedArray.getString(R.styleable.TitleBar_right_text); srcLeftImageId = typedArray.getResourceId(R.styleable.TitleBar_left_image, 0); srcRightImageId = typedArray.getResourceId(R.styleable.TitleBar_right_image, 0); typedArray.recycle(); initView(context); } public TitleBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } public void initView(Context context) { LayoutInflater.from(context).inflate(R.layout.title_bar_layout, this, true); setBackgroundColor(barBgColor); // 左邊按鈕區域 vgLeft = findViewById(R.id.layoutLeft); ivIconLeft = findViewById(R.id.ivLeft); ivIconLeft.setImageResource(srcLeftImageId); tvLeft = findViewById(R.id.tvLeft); tvLeft.setText(leftText); // 右邊按鈕區域 vgRight = findViewById(R.id.layoutRight); ivIconRight = findViewById(R.id.ivRight); ivIconRight.setImageResource(srcRightImageId); tvRight = findViewById(R.id.tvRight); tvRight.setText(rightText); // 标題文字 tvTitle = findViewById(R.id.tvTitle); tvTitle.setTextColor(textColor); setTitle(titleString); } public void setTitle(String title) { if (!TextUtils.isEmpty(title)) { tvTitle.setText(title); } } public void setLeftText(String leftText) { this.leftText = leftText; if (this.leftText == null) this.leftText = ""; tvLeft.setText(this.leftText); } public void setLeftImage(int resImage) { ivIconLeft.setImageResource(resImage); } public void setRightText(String rightText) { this.rightText = rightText; if (this.rightText == null) this.rightText = ""; tvRight.setText(this.rightText); } public void setRightImage(int resImage) { ivIconRight.setImageResource(resImage); } public void setLeftClickListener(OnClickListener onClickListener) { vgLeft.setOnClickListener(onClickListener); } public void setRightClickListener(OnClickListener onClickListener) { vgRight.setOnClickListener(onClickListener); }}
至此我們就完成了個複合型的标題欄了,現在放在activity_main.xml裡看看效果:
<?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.customerview.TitleBar android:id="@+id/titleBar" android:layout_width="match_parent" android:layout_height="wrap_content" app:bg_color="@color/colorAccent" app:left_image="@android:drawable/btn_star" app:left_text="首頁" app:right_image="@android:drawable/btn_dialog" app:right_text="關閉" app:text_color="#ff0" app:title_text="标題一" /> <com.example.customerview.TitleBar android:layout_width="match_parent" android:layout_height="wrap_content" app:title_text="标題二" /> <com.example.customerview.TitleBar android:layout_width="match_parent" android:layout_height="wrap_content" app:right_image="@android:drawable/btn_dialog" app:right_text="關閉" app:bg_color="@android:color/holo_orange_dark" app:title_text="标題三" />LinearLayout>
MainActivity.java
package com.example.customerview;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Toast;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TitleBar tb = findViewById(R.id.titleBar); tb.setLeftClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "Left Click", Toast.LENGTH_LONG).show(); } }); tb.setRightClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "Right Click", Toast.LENGTH_LONG).show(); } }); }}
歡迎關注《口袋裡的安卓》 或 加入QQ群聊《口袋裡的安卓》