TextView
TextView 主要用于在界面上显示一段文本信息
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#00ff00"
android:textSize="24sp"
android:text="This is TextView"
tools:ignore="HardcodedText" />
</LinearLayout>
可配置的属性如下:
-
android:id
给当前控件定义一个唯一标识符
-
android:layout_width、android:layout_height
指定控件的宽度和高度,可选值有三个:match_parent、wrap_content 和固定值,match_parent 表示让当前控件的大小和父布局的大小一样,wrap_content 表示让当前控件的大小能刚好包含里面的内容,固定值表示给控件指定一个固定的尺寸,单位一般用 dp
-
android:gravity
指定文字的对齐方式,可选值有 top、bottom、start、end、center 等,可以用 | 来同时指定多个值,这里的 center 表示文字在垂直和水平方向都居中对齐
-
android:textColor
指定文字的颜色
-
android:textSize
指定文字的大小
Button
Button 可配置的属性和 TextView 是差不多的
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"
tools:ignore="HardcodedText" />
</LinearLayout>
接下来我们可以在 MainActivity 中为 Button 的点击事件注册一个监听器
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
// 在此处添加逻辑
}
}
}
也可以实现 View.OnClickListener 接口,并重写 onClick() 方法,然后调用 button 的 setOnClickListener() 方法将 MainActivity 的实例传进去
class MainActivity : AppCompatActivity(), View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener(this)
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.button -> {
// 在此处添加逻辑
}
}
}
}
EditText
EditText 允许用户在控件里输入和编辑内容,并可以在程序中对这些内容进行处理
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type something here"
android:maxLines="2"
tools:ignore="HardcodedText" />
-
android:hint
指定一段提示性文本
-
android:maxLines
指定了 EditText 的最大行数为两行,当输入的内容超过两行时,文本会向上滚动,EditText 不会再继续拉伸
ImageView
ImageView 用于在界面上展示图片的一个控件,图片通常放在 drawable 开头的目录下
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img_1" />
ProgressBar
ProgressBar 用于在界面上显示一个进度条,表示我们的程序正在加载一些数据
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
旋转的进度条表明我们的程序正在加载数据,那数据总会有加载完的时候,如何让进度条在数据加载完时消失呢?这里我们就需要使用 android:visibility 属性,可选值有三个:visible、invisible 和 gone,visible 表示控件是可见的,invisible 表示控件不可见,但它仍然占据着原来的屏幕和大小,gone 表示控件不仅不可见,而且不占用屏幕任何控件。所以我们可以在代码中设置控件的可见性,使用的是 setVisibility() 方法,允许传入 View.VISIBLE、View.INVISIBLE 和 View.GONE
另外,我们可以给 ProgressBar 指定不同的样式,默认是圆形进度条,通过 style 属性可以将它指定成水平进度条
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:max="100" />
</LinearLayout>
我们通过 android:max 属性给进度条设置一个最大值,然后在代码中动态地更改进度条的进度
class MainActivity : AppCompatActivity(), View.OnClickListener {
...
override fun onClick(v: View?) {
when (v?.id) {
R.id.button -> {
progressBar.progress = progressBar.progress + 10
}
}
}
}
AlertDialog
AlertDialog 可以在当前界面弹出一个置顶于所有界面元素之上的对话框,一般用于提示一些非常重要的内容或者警告信息
class MainActivity : AppCompatActivity(), View.OnClickListener {
...
override fun onClick(v: View?) {
when (v?.id) {
R.id.button -> {
AlertDialog.Builder(this).apply {
setTitle("This is Dialog")
setMessage("Something important")
setCancelable(false)
setPositiveButton("OK") {dialog, which ->}
setNegativeButton("Cancel") {dialog, which -> }
show()
}
}
}
}
}
创建自定义控件
在 Android 中,我们所用的所有控件都是直接或间接继承自 View 的,所用的所有布局都是直接或间接继承自 ViewGroup 的。View 是 Android 中最基本的一种 UI 组件,我们所使用的各种控件其实就是在 View 的基础上又添加了各自特有的功能。而 ViewGroup 则是一种特殊的 View,它可以包含很多子 View 和子 ViewGroup,是一个用于放置控件和布局的容器
当系统自带的控件不能满足我们的需求时,可以利用上面的继承结构来创建自定义控件,下面介绍两种创建自定义控件的简单方法:
1. 引入布局
相信创建一个标题栏布局对你来说不是一件难事,只需要加入两个 Button 和一个 TextView。但如果每个 Activity 都需要一个这样的标题栏,就会导致代码的大量重复。这时,我们可以利用引入布局的方式来解决这个问题
新建一个 title.xml 布局文件
<?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="wrap_content"
android:background="@drawable/title_bg">
<Button
android:id="@+id/titleBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="@drawable/back_bg"
android:text="Back"
android:textColor="#fff"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/titleText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:text="Title Text"
android:textColor="#fff"
android:textSize="24sp"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/titleEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="@drawable/back_bg"
android:text="Edit"
android:textColor="#fff"
tools:ignore="HardcodedText" />
</LinearLayout>
标题栏布局已经编写完成,剩下的就是如何在程序中使用这个标题栏了,修改 activity_main.xml 中的代码如下:
<?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">
<include layout="@layout/title" />
</LinearLayout>
最后别忘了在 MainActivity 中将系统自带的标题栏隐藏掉
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
}
}
2. 创建自定义控件
引入布局的方式确实可以解决重复代码的问题,但如果布局中有一些控件要求能够响应事件,我们还是需要在 Activity 中为这些控件单独编写一次事件注册的代码,这种情况最好是使用自定义控件的方式来解决
新建 TitleLayout 继承自 LinearLayout,让它成为我们自定义的标题栏控件
class TitleLayout(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
init {
LayoutInflater.from(context).inflate(R.layout.title, this)
}
}
我们在 TitleLayout 的主构造函数中声明了 Context 和 AttributeSet 这两个参数,在布局中引入 TitleLayout 控件时就会调用这个构造函数
然后在 init 结构体中需要对标题栏布局进行动态加载,通过 LayoutInflater 的 from() 方法可以构建出一个 LayoutInflater 对象,然后调用 inflate() 方法可以动态加载一个布局文件。inflate() 方法接收两个参数:第一个参数是要加载的布局文件的 id,这里传入 R.layout.title;第二个参数是给加载好的布局再添加一个父布局,这里我们想要指定为 TitleLayout,于是传入 this
自定义控件已经创建好了,接下来我们需要在布局文件中添加这个自定义控件,修改 activity_main.xml 中的代码,如下所示:
<?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">
<com.example.uiwidgettest.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
下面我们尝试为标题栏中的按钮注册点击事件,修改 TitleLayout 中的代码,如下所示:
class TitleLayout(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
init {
LayoutInflater.from(context).inflate(R.layout.title, this)
titleBack.setOnClickListener {
val activity = context as Activity
activity.finish()
}
titleEdit.setOnClickListener {
Toast.makeText(context, "You clicked Edit button", Toast.LENGTH_SHORT).show()
}
}
}