一、自定义控件和引入布局
1、引入布局
1.1 创建一个新的布局
<?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="match_parent">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ic_launcher_foreground"
android:text="Back" />
<TextView
android:id="@+id/text"
android:layout_width="74dp"
android:layout_height="48dp"
android:layout_marginStart="30dp"
android:gravity="center"
android:layout_marginTop="4dp"
android:text="通知栏"
android:textColor="#2a2"
android:textSize="22dp" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:background="@drawable/ic_launcher_foreground"
android:text="Next"/>
</LinearLayout>
android:background
用于为布局或控件指定一个背景,可以使用颜色或图片来进行填充。
android:layout_marginTop
它可以指定控件在上下左右方向上偏移的距离,当然也可以使用android:layout_marginStart或android:layout marginTop等属性来单独指定控件在某个方向上偏移的距离。
1.2 导入其他layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity">
<include layout="@layout/fist1"/>
</LinearLayout>
<include layout="@layout/fist1"/>
导入设置好的文件fist1
1.3 隐藏系统自带的标题栏
这个时候是有系统自带的标题栏,我们需要把他隐藏掉,代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar bar = getSupportActionBar();
if(bar != null){
//隐藏状态栏
bar.hide();
}
}
这里我们调用了getSupportActionBar()
方法来获得ActionBar
的实例,然后再调用ActionBar的hide()
方法将标题栏隐藏起来
也可以直接在目录res->values->themes.xml下修改为:
<style name="Base.Theme.MyApplication4" parent="Theme.Material3.Light.NoActionBar">
Theme.Material3.Light.NoActionBar表示没有标题栏
结果如下:
2、创建自定义控件
新建Fist1Layout继承自LinearLayout,.让它成为我们自定义的标题栏控件,代码如下所示:
public class Fist1Layout extends LinearLayout {
public Fist1Layout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
/**
* 使用from获取一个LayoutInflater对象,如何使用inflate方法,注意传递的this是Fist1
* Fist1继承了LinearLayout,实际传递的父布局是LinearLayout
*/
Fist1Binding fist1Binding = Fist1Binding.inflate(LayoutInflater.from(context), this, true);
}
}
首先我们重写了LinearLayout
中带有两个参数的构造函数,在布局中引入TitleLayout
控件就会调用这个构造函数。然后在构造函数中需要对标题栏布局进行动态加载,这就要借助LayoutInflater
来实现了。
这个用法Fist1Binding.inflate(LayoutInflater.from(context), this, true)
用于通过数据绑定(Data Binding)库来填充布局,并且将填充后的视图根元素设置为当前自定义视图(Fist1Layout
)的子视图。
在Android中,数据绑定是一种技术,它允许将布局文件中的UI组件直接绑定到数据源,并在布局文件中动态地更新UI,从而避免了手动操作视图的繁琐步骤。
Fist1Binding.inflate()
: 这是数据绑定库提供的一个静态方法,用于将布局文件fist1.xml
填充到一个视图层次结构中,并返回绑定类的实例。
LayoutInflater.from(context)
: 这是一个静态方法,用于获取LayoutInflater
的实例。LayoutInflater
是Android中用于解析布局文件的类,它可以将XML布局文件转换为视图对象。通过LayoutInflater.from(context)
,我们获得一个适用于当前上下文(context
)的LayoutInflater
实例。
this
: 这代表当前的自定义视图Fist1Layout
。填充后的布局作为当前视图的子视图添加是通过将this
作为第二个参数传递给Fist1Binding.inflate()
来实现的。这样做后,填充后的布局将成为Fist1Layout
的子视图。
true
: 这是一个标志位,表示是否将填充后的布局自动添加到Fist1Layout
中。
现在自定义控件已经创建好了,我们需要在布局文件中加入这个控件,activity_mainxml中代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity">
<!-- <include layout="@layout/fist1"/>-->
<com.example.myapplication4.Fist1Layout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
添加自定义控件和添加普通控件的方式基本是一样的,只不过在添加自定义控件的时候,我们需要指明控件的完整类名,包名在这里是不可以省略的。
重新运行程序,你会发现此时效果和使用引入布局方式的效果是一样的。
接下来我们为两个按钮注册监听事件,代码如下:
public class Fist1Layout extends LinearLayout {
public Fist1Layout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
// 使用Fist1Binding来填充布局,并将根视图设置为Fist1Layout
Fist1Binding fist1Binding = Fist1Binding.inflate(LayoutInflater.from(context), this, true);
// 直接使用Fist1Binding提供的按钮引用
fist1Binding.button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
((Activity) getContext()).finish();
}
});
fist1Binding.button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getContext(), "消息已发送", Toast.LENGTH_SHORT).show();
}
});
}
}
点击一下Next按钮,效果如图所示:
这样的话,每当我们在一个布局中引入TitleLayout
时,返回按钮和编辑按钮的点击事件就已经自动实现好了,这就省去了很多编写重复代码的工作。