Android 封装自定义组件
Haiya Lv3

Android 开发中,封装自定义组件可提升代码复用性。通过创建自定义视图,开发者能将常用 UI 或功能模块抽象成独立组件,便于在不同项目中重复使用,增强应用的模块化和可维护性。

本文以封装一个列表中的 Item 为例,介绍如何封装自定义组件。

该组件的效果是:

  • 具有左右两个 TextView,左侧 TextView 作为标题列,右侧 TextView 作为值列;
  • 右侧 TextView 超出范围时,显示省略号,点击后弹出 Dialog 展示完整值

效果图

列表效果 Dialog 效果

创建自定义布局文件

res/layout 下创建一个 layout_list_item.xml,文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingVertical="5dp">

<TextView
android:id="@+id/left_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:layout_marginEnd="10dp"
android:textStyle="bold" />

<TextView
android:id="@+id/right_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3" />

</LinearLayout>

创建类

新建一个继承自 LinearLayout 的类 ListItemLayout,文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.example.custom.R;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;

public class ListItemLayout extends LinearLayout {
private TextView leftTextView;
private TextView rightTextView;

public ListItemLayout(Context context) {
super(context);
init(context);
}

public ListItemLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

public ListItemLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

private void init(Context context) {
LayoutInflater.from(context).inflate(R.layout.layout_list_item, this, true);
leftTextView = findViewById(R.id.left_text_view);
rightTextView = findViewById(R.id.right_text_view);

rightTextView.setEllipsize(TextUtils.TruncateAt.END);
rightTextView.setSingleLine(true);

rightTextView.setOnClickListener(v -> new MaterialAlertDialogBuilder(context)
.setTitle(leftTextView.getText())
.setMessage(rightTextView.getText())
.show());
}

public void setLeftText(String text) {
leftTextView.setText(text);
}

public void setRightText(String text) {
rightTextView.setText(text);
}

public void setRightTextColor(int color) {
rightTextView.setTextColor(color);
}
}

使用

MainActivity 中使用 ListItemLayout 类,代码如下:

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:paddingHorizontal="20dp">

<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content">

<LinearLayout
android:id="@+id/layout_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="30dp" />
</com.google.android.material.card.MaterialCardView>

</LinearLayout>


</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});

// 数据
String[][] data = {
{"姓名", "杜智斌"},
{"性别", "男"},
{"实人认证", "已认证", "#369650"},
{"身份证号码", "610630197509152020"},
{"出生日期", "1975年09月15日"},
{"详细地址", "陕西省延安市宜川县南环路478-16号5栋2单元301-1号门"},
{"证件状态", "已过期", "#FF0000"},
};

// 使用自定义布局
LinearLayout container = findViewById(R.id.layout_container);

for (String[] row : data) {
ListItemLayout listItemLayout = new ListItemLayout(this);
listItemLayout.setLeftText(row[0]);
listItemLayout.setRightText(row[1]);
if (row.length == 3) {
listItemLayout.setRightTextColor(Color.parseColor(row[2]));
}
container.addView(listItemLayout);
}
}
}
由 Hexo 驱动 & 主题 Keep