4. UI 开发
4. UI 开发
1. 常用控件
1. TextView
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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"/>
</LinearLayout>
- layout_width
- match_parent:匹配父布局
- wrap_content:包裹内容
- 50 dp:与屏幕密度无关的尺寸单位
- gravity:对齐方式
- 用 | 指定多个值
- top
- bottom
- start
- end
- center
2. Button
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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:textAllCaps="false"
android:text="Button" />
</LinearLayout
-
textAllCaps:表示是否改为大写
-
使用函数式API的方式来注册监听器,也可以使用实现接口的方式来进行注册
3. EditText
- 应用场景:发短信、发微博、聊QQ等
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type something here"
android:maxLines="2"
/>
</LinearLayout>
-
hint:提示性的文本
-
maxLines:超过 n 行文本就会向上滚动,EditText 则不会再继续拉伸
-
应用:如通过点击按钮获取 EditText 中输入的内容
override fun onClick(v: View?) {
when (v?.id) {
R.id.button -> {
val inputText = editText.text.toString()
Toast.makeText(this, inputText, Toast.LENGTH_SHORT).show()
}
}
}
4. ImageView
-
资源
- 图片通常放在以 drawable 开头的目录下的,并且要带上具体的分辨率
- 即 res/drawable-xxhdpi 中
- 【这里的xx就是xx还是代表某个数值?】
- 图片通常放在以 drawable 开头的目录下的,并且要带上具体的分辨率
-
xml 代码
-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> ... <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/img_1" /> </LinearLayout> -
src:指定图片
- 【能自动识别对应dpi吗】
-
-
动态修改图片
-
override fun onClick(v: View?) { when (v?.id) { R.id.button -> { // 点到 button 则替换 Res imageView.setImageResource(R.drawable.img_2) } } }
-
5. ProgressBar
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
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="?android:attr/progressBarStyleHorizontal"
android:max="100"
/>
</LinearLayout>
-
style:风格
-
默认为圆圈
-
可以设置可见性属性
- VISIBLE:可见
- INVISIBLE:不可见
- GONE:不可见且不占用屏幕空间
-
// 切换可见性 override fun onClick(v: View?) { when (v?.id) { R.id.button -> { if (progressBar.visibility == View.VISIBLE) { progressBar.visibility = View.GONE } else { progressBar.visibility = View.VISIBLE } } } }
-
-
progressBarStyleHorizontal 为进度条
-
此时可以设置最大值,实现进度条进度
-
override fun onClick(v: View?) { when (v?.id) { R.id.button -> { progressBar.progress = progressBar.progress + 10 } } }
-
-
6. AlertDialog
- 在当前界面弹出一个对话框
- 这个对话框是置顶于所有界面元素之上的,能够屏蔽其他控件的交互能力
- 因 AlertDialog 一般用于提示一些非常重要的内容或者警告信息。
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()
}
}
}
}
2. 布局
| 场景 | 推荐layout | 理由 |
|---|---|---|
| 通用复杂界面 | ConstraintLayout | 扁平、高性能、易维护 |
| 简单横向/纵向排列(<4 个 View) | LinearLayout | 代码最少,够用 |
| Fragment 容器/简单叠加 | FrameLayout | 轻量、语义清晰 |
| 长列表 | RecyclerView | 复用机制、内存安全 |
| 复杂滚动交互 | CoordinatorLayout | 类似 Fragment,Behavior 机制 |
| 严格二维网格 | GridLayout | 行列语义明确 |
- 布局的内部除了放置控件外,也可以放置布局
1. LinearLayout
1. 排列方向 orientation
- 水平:
android:orientation="horizontal" - 垂直:
android:orientation="vertical"- 注意
- 如果 Layout 的
orientation为水平,那么 View 的layout_width就不能为match_parent- 因为这样一个控件就填满了
- 如果 Layout 的
- 注意
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
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:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 2" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 3" />
</LinearLayout>
2. layout_gravity
- 注意
- 如果 Layout 的
orientation为水平,那么 View 的layout_gravity只能是垂直方向的选择 - 此时若干个控件仍会在水平方向线性排列,而高度根据具体的
layout_gravity设置
- 如果 Layout 的
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
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:layout_gravity="top"
android:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Button 2" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="Button 3" />
</LinearLayout>
3. layout_weight
- 此时
layout_width指定为 0 就行 layout_weight会在排除掉固定宽度后,剩下所有控件根据权重占据大小
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/input_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Type something"
/>
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send"
/>
</LinearLayout>
2. RelativeLayout
- 相对于父布局
layout_alignParentLeftlayout_alignParentToplayout_alignParentRightlayout_alignParentBottomlayout_centerInParent- 相对于控件
- 只能引用之前的控件
layout_abovelayout_belowlayout_toLeftOflayout_toRightOf
<RelativeLayout 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:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="Button 2" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Button 3" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="Button 4" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="Button 5" />
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Button 3" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/button3"
android:layout_toLeftOf="@id/button3"
android:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/button3"
android:layout_toRightOf="@id/button3"
android:text="Button 2" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/button3"
android:layout_toLeftOf="@id/button3"
android:text="Button 4" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/button3"
android:layout_toRightOf="@id/button3"
android:text="Button 5" />
</RelativeLayout>
3. FrameLayout
- 帧布局
- 默认摆放在布局的左上角
- 且后定义的会覆盖之前定义的控件
- 使用
layout_gravity指定对齐方式 - 在
Fragment场景使用的多一些
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="This is TextView"
/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="Button"
/>
</FrameLayout>
3. 自定义控件
【控件继承图】
- 引入布局:解决重复布局的问题
- 自定义控件:解决重复逻辑的问题
1. 引入布局
- 在 layout 目录建立一个新的布局 title.xml
- 在 title.xml 中编写重复布局
- 在需要使用的 xml 中直接引用布局
<include layout="@layout/title" />- 引用和文件名对应
2. 创建自定义控件
- 场景:对于标题的返回按钮,每次按返回键,一定是销毁当前 Activity,因此有重复逻辑
- 新建 layout 类继承某个 layout
- 在布局文件中添加这个自定义控件
- 需要指明控件的完整类名,包名在这里是不可以省略的
- 之后其他 Activity 可以直接使用这个控件来销毁 Activity
class TitleLayout(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
init {
LayoutInflater.from(context).inflate(R.layout.title, this) // 对标题栏布局进行动态加载
// 构造出一个 LayoutInflater 对象, 调用 inflate 动态加载一个布局文件
// 第一个参数是要加载的布局文件的id, 第二个参数是给加载好的布局再添加一个父布局
// 【为什么父布局是本身】
titleBack.setOnClickListener {
val activity = context as Activity // 强制转换
activity.finish()
}
titleEdit.setOnClickListener {
Toast.makeText(context, "You clicked Edit button", Toast.LENGTH_SHORT).show()
}
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.uicustomviews.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
4. ListView
- 场景:有大量的数据需要展示,比如查看QQ聊天记录,翻阅微博最新消息
1. 简单用法
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
class MainActivity : AppCompatActivity() {
private val data = listOf("Apple", "Banana", "Orange", "Watermelon",
"Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango",
"Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape",
"Pineapple", "Strawberry", "Cherry", "Mango")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 设置 listView 数据
val adapter = ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data) // 通过适配器处理数据
val listView: ListView = findViewById(R.id.listView)
listView.adapter = adapter
}
}
2. 定制界面
- 定义一个实体类,作为 ListView 适配器的适配类型
class Fruit(val name:String, val imageId: Int) // imageId 表示水果对应图片的资源 id
- 布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp">
<ImageView
android:id="@+id/fruitImage"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"/>
<TextView
android:id="@+id/fruitName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp" />
</LinearLayout>
-
layout_marginLeft:边距
-
自定义适配器
class FruitAdapter(activity: Activity, val resourceId: Int, data: List<Fruit>) :
ArrayAdapter<Fruit>(activity, resourceId, data) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { // 每个子项滚动到屏幕内的时候会被调用
val view = LayoutInflater.from(context).inflate(resourceId, parent, false)
val fruitImage: ImageView = view.findViewById(R.id.fruitImage)
val fruitName: TextView = view.findViewById(R.id.fruitName)
val fruit = getItem(position) // 获取当前项的Fruit实例
if (fruit != null) {
fruitImage.setImageResource(fruit.imageId) // 相当于 imageView.setImageResource(R.drawable.apple_pic)
fruitName.text = fruit.name // 相当于 textView.text = "apple"
}
return view
}
}
- Main 代码
class MainActivity : AppCompatActivity() {
private val fruitList = ArrayList<Fruit>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initFruits() // 初始化水果数据
val adapter = FruitAdapter(this, R.layout.fruit_item, fruitList)
listView.adapter = adapter
}
private fun initFruits() {
repeat(2) {
fruitList.add(Fruit("Apple", R.drawable.apple_pic))
fruitList.add(Fruit("Banana", R.drawable.banana_pic))
fruitList.add(Fruit("Orange", R.drawable.orange_pic))
fruitList.add(Fruit("Watermelon", R.drawable.watermelon_pic))
fruitList.add(Fruit("Pear", R.drawable.pear_pic))
fruitList.add(Fruit("Grape", R.drawable.grape_pic))
fruitList.add(Fruit("Pineapple", R.drawable.pineapple_pic))
fruitList.add(Fruit("Strawberry", R.drawable.strawberry_pic))
fruitList.add(Fruit("Cherry", R.drawable.cherry_pic))
fruitList.add(Fruit("Mango", R.drawable.mango_pic))
}
}
}
3. 提升效率
- 自定义适配器现在存在两个问题
- FruitAdapter 的 getView() 方法每次都会重新加载布局
- 解决方法:getView() 的 convertView 参数缓存了布局
- convertView 为 null 则加载
- convertView 存在则重用
- 解决方法:getView() 的 convertView 参数缓存了布局
- 每次 getView() 会调用 findViewById() 方法来获取一次控件的实例
- 使用内部类 ViewHolder 对 ImageView 和 TextView 的控件实例进行缓存
- 当 convertView 为 null 的时候
- 创建一个 ViewHolder 对象,并将控件的实例存放在 ViewHolder 里,然后调用 View 的 setTag() 方法,将 ViewHolder 对象存储在 View 中
- 当 convertView 不为 null 的时候
- 则调用 View 的 getTag() 方法,把 ViewHolder重新取出。
- 当 convertView 为 null 的时候
- 使用内部类 ViewHolder 对 ImageView 和 TextView 的控件实例进行缓存
- FruitAdapter 的 getView() 方法每次都会重新加载布局
class FruitAdapter(activity: Activity, val resourceId: Int, data: List<Fruit>) :
ArrayAdapter<Fruit>(activity, resourceId, data) {
inner class ViewHolder(val fruitImage: ImageView, val fruitName: TextView)
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view: View
val viewHolder: ViewHolder
if (convertView == null) { // 不存在则新建布局
view = LayoutInflater.from(context).inflate(resourceId, parent, false)
val fruitImage: ImageView = view.findViewById(R.id.fruitImage)
val fruitName: TextView = view.findViewById(R.id.fruitName)
viewHolder = ViewHolder(fruitImage, fruitName)
view.tag = viewHolder
} else { // 读取缓存
view = convertView
viewHolder = view.tag as ViewHolder
}
val fruit = getItem(position) // 获取当前项的Fruit实例
if (fruit != null) {
viewHolder.fruitImage.setImageResource(fruit.imageId)
viewHolder.fruitName.text = fruit.name
}
return view
}
}
4. 点击事件
listView.setOnItemClickListener { _, _, position, _ ->
val fruit = fruitList[position]
Toast.makeText(this, fruit.name, Toast.LENGTH_SHORT).show()
}
5. RecycleView
在 projectStructure 的 dependencies 中搜索 recyclerview
在 app/build.gradle 中添加代码 implementation libs.androidx.recyclerview
【细节和水平/瀑布流/网格布局】
0. 代码汇总
-
修改文件
-
second_layout
-
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar2" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" android:theme="?attr/actionBarTheme" /> <Button android:id="@+id/button2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Back" /> <Button android:id="@+id/button3" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Quit App" /> <Button android:id="@+id/button4" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Go third" /> <Button android:id="@+id/button5" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Go forth" /> </LinearLayout>
-
-
MainActivity2
-
package com.example.helloworld import android.content.Context import android.content.Intent import android.os.Bundle import android.util.Log import android.widget.ArrayAdapter import android.widget.Button import android.widget.ListView import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar class MainActivity2 : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.second_layout) // toolbar 部分 val toolbar: Toolbar = findViewById(R.id.toolbar2) setSupportActionBar(toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) // 设置返回按钮 toolbar.setNavigationOnClickListener { finish() } // 设置结束 act2 ActivityCollector.addActivity(this) // 从前一个 Activity 接收数据 val extraData1 = intent.getStringExtra("param1") val extraData2 = intent.getStringExtra("param2") Log.d("Activity2", "param1 is $extraData1, param2 is $extraData2") // 返回数据(但是未实现) val button2: Button = findViewById(R.id.button2) // 通过 id 找到 view, 并指明类型为 button button2.setOnClickListener { val intent = Intent().apply { putExtra("data_return", "Hello Activity1") } setResult(RESULT_OK, intent) finish() } // 关闭所有 Activity val button3: Button = findViewById(R.id.button3) button3.setOnClickListener { ActivityCollector.finishAll() } val button4: Button = findViewById(R.id.button4) button4.setOnClickListener { startNewActivity(this, MainActivity3::class.java) } val button5: Button = findViewById(R.id.button5) button5.setOnClickListener { startNewActivity(this, MainActivity4::class.java) } } }
-
-
-
增加文件
-
MainActivity3
-
package com.example.helloworld import android.app.Activity import android.content.Context import android.content.Intent import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.Button import android.widget.ImageView import android.widget.ListView import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar class Fruit(val name:String, val imageId: Int) // imageId 表示水果对应图片的资源 id class FruitAdapter(activity: Activity, val resourceId: Int, data: List<Fruit>) : ArrayAdapter<Fruit>(activity, resourceId, data) { inner class ViewHolder(val fruitImage: ImageView, val fruitName: TextView) override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val view: View val viewHolder: ViewHolder if (convertView == null) { // 不存在则新建布局 view = LayoutInflater.from(context).inflate(resourceId, parent, false) val fruitImage: ImageView = view.findViewById(R.id.fruitImage) val fruitName: TextView = view.findViewById(R.id.fruitName) viewHolder = ViewHolder(fruitImage, fruitName) view.tag = viewHolder } else { // 读取缓存 view = convertView viewHolder = view.tag as ViewHolder } val fruit = getItem(position) // 获取当前项的Fruit实例 if (fruit != null) { viewHolder.fruitImage.setImageResource(fruit.imageId) viewHolder.fruitName.text = fruit.name } return view } } class MainActivity3 : BaseActivity() { private val fruitList = ArrayList<Fruit>() private val data = listOf("Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango", "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.third_layout) ActivityCollector.addActivity(this) // toolbar 部分 val toolbar: Toolbar = findViewById(R.id.toolbar3) setSupportActionBar(toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) toolbar.setNavigationOnClickListener { finish() } initFruits() // 初始化水果数据 val adapter = FruitAdapter(this, R.layout.fruit_item, fruitList) // 使用 fruit_item layout val listView: ListView = findViewById(R.id.listView) listView.adapter = adapter listView.setOnItemClickListener { _, _, position, _ -> val fruit = fruitList[position] Toast.makeText(this, fruit.name, Toast.LENGTH_SHORT).show() } } private fun initFruits() { val imageId = R.drawable.apple_pic repeat(3) { data.forEach { fruitList.add(Fruit(it, imageId)) } } } }
-
-
MainActivity4.kt
-
package com.example.helloworld import android.app.Activity import android.content.Context import android.content.Intent import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.Button import android.widget.ImageView import android.widget.ListView import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView class FruitAdapter2(val fruitList: List<Fruit>) : RecyclerView.Adapter<FruitAdapter2.ViewHolder>() { inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val fruitImage: ImageView = view.findViewById(R.id.fruitImage) val fruitName: TextView = view.findViewById(R.id.fruitName) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.fruit_item, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val fruit = fruitList[position] holder.fruitImage.setImageResource(fruit.imageId) holder.fruitName.text = fruit.name } override fun getItemCount() = fruitList.size } class MainActivity4 : BaseActivity() { private val fruitList = ArrayList<Fruit>() private val data = listOf("Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango", "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.forth_layout) ActivityCollector.addActivity(this) // toolbar 部分 val toolbar: Toolbar = findViewById(R.id.toolbar4) setSupportActionBar(toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) toolbar.setNavigationOnClickListener { finish() } initFruits() // 初始化水果数据 val layoutManager = LinearLayoutManager(this) val recyclerView: RecyclerView = findViewById(R.id.recyclerView) recyclerView.layoutManager = layoutManager val adapter = FruitAdapter2(fruitList) recyclerView.adapter = adapter } private fun initFruits() { val imageId = R.drawable.apple_pic repeat(3) { data.forEach { fruitList.add(Fruit(it, imageId)) } } } }
-
-
third_layout.xml
-
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar3" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" android:theme="?attr/actionBarTheme" /> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
-
-
forth_layout.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" android:orientation="vertical"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar4" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" android:theme="?attr/actionBarTheme" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
-
-
fruit_item.xml
-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp"> <ImageView android:id="@+id/fruitImage" android:layout_width="40dp" android:layout_height="40dp" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp"/> <TextView android:id="@+id/fruitName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp" /> </LinearLayout>
-
-
Util.kt
-
package com.example.helloworld import android.app.Activity import android.content.Context import android.content.Intent import android.os.Bundle import android.util.Log import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.google.android.material.snackbar.Snackbar // 输出当前是哪一个 Activity open class BaseActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Log.d("BaseActivity", "${javaClass.simpleName} is created") } override fun onStart() { super.onStart() Log.d("BaseActivity", "${javaClass.simpleName} is started") } override fun onResume() { super.onResume() Log.d("BaseActivity", "${javaClass.simpleName} is resumed") } } // Activity 管理 object ActivityCollector { private val activities = ArrayList<Activity>() fun addActivity(activity: Activity){ activities.add(activity) } fun removeActivity(activity: Activity){ activities.remove(activity) } fun finishAll() { activities.forEach { if(!it.isFinishing) { it.finish() } } activities.clear() } } fun startNewActivity(context: Context, targetActivity: Class<out AppCompatActivity>) { val intent = Intent(context, targetActivity) context.startActivity(intent) } // 调用方法 startNewActivity(this, ActivityClass::class.java) fun startNewActivity(context: Context, targetActivity: Class<out AppCompatActivity>, data1: String, data2: String) { val intent = Intent(context, targetActivity).apply { putExtra("param1", data1) putExtra("param2", data2) } context.startActivity(intent) } fun startNewActivityAndFinish(activity: Activity, targetActivity: Class<out AppCompatActivity>) { val intent = Intent(activity, targetActivity) activity.startActivity(intent) activity.finish() } // 调用方法 "This is Toast".showToast(context, Toast.LENGTH_LONG) fun String.showToast(context: Context, duration: Int = Toast.LENGTH_SHORT) { Toast.makeText(context, this, duration).show() } fun Int.showToast(context: Context, duration: Int = Toast.LENGTH_SHORT) { Toast.makeText(context, this, duration).show() } /* 调用方法 * view.showSnackBar("This is SnackBar", "Action") { * // * 处理具体的逻辑 * } **/ fun View.showSnackBar(text: String, actionText: String? = null, duration: Int = Snackbar.LENGTH_SHORT, block: (() -> Unit)? = null) { val snackBar = Snackbar.make(this, text, duration) if (actionText != null && block != null) { snackBar.setAction(actionText) { block() } } snackBar.show() } fun View.showSnackBar(resId: Int, actionResId: Int? = null, duration: Int = Snackbar.LENGTH_SHORT, block: (() -> Unit)? = null) { val snackBar = Snackbar.make(this, resId, duration) if (actionResId != null && block != null) { snackBar.setAction(actionResId) { block() } } snackBar.show() } -
drawable/apple_pic.png
-

浙公网安备 33010602011771号