安卓开发学习笔记_UI开发_更强大的滚动控件: RecyclerView
RecyclerView属于新增控件, 要在项目的build.gradle中添加RecyclerView库的依赖.
打开app/build.gradle文件, 在dependencies闭包中添加如下内容:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}
当不确定版本号时, 可以填入1.0.0, android studio会自动更新
RecyclerView的基本用法
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 因为没有内置在系统sdk中, 所以要写完整的包路径 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
适配器
// fruitList数据源
class FruitAdapter(val fruitList: List<Fruit>): RecyclerView.Adapter<FruitAdapter.ViewHolder>()
{
// view通常就是RecyclerView子项的最外层布局.
inner class ViewHolder(view: View): RecyclerView.ViewHolder(view){
val fruitImage: ImageView = view.findViewById(R.id.fruitImage)
val fruitName: TextView = view.findViewById(R.id.fruitName)
}
// 用于创建ViewHolder实例
// 加载fruit_itme布局, 将加载出来的布局传入构造函数, 返回ViewHolder实例
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.fruit_item, parent, false)
return ViewHolder(view)
}
// 对RecyclerView子项的数据进行赋值, 会在每个子项滚动到屏幕内的时候执行
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val fruit = fruitList[position]
holder.fruitImage.setImageResource(fruit.imageId)
}
// 返回数据源的长度
override fun getItemCount() = fruitList.size
}
修改MainActivity中的代码
class MainActivity : AppCompatActivity() {
private val fruitList = ArrayList<Fruit>()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
initFruits()
// 创建一个LinearLayoutManager对象
val layoutManager = LinearLayoutManager(this)
// 指定recyclerView的布局方式为LinearLayoutManager
binding.recyclerView.layoutManager = layoutManager
val adapter = FruitAdapter(fruitList)
binding.recyclerView.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))
}
}
}
实现横向滚动和瀑布流布局
横向滚动
要实现横向滚动的话, 应该把fruit_time的元素改成垂直排列.
修改fruit_item的代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/fruitImage"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="10dp"/>
<TextView
android:id="@+id/fruitName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="10dp" />
</LinearLayout>
修改MainActivity中的代码
class MainActivity : AppCompatActivity() {
private val fruitList = ArrayList<Fruit>()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
...
layoutManager.orientation = LinearLayoutManager.HORIZONTAL
...
}
...
}
瀑布流
RecyclerView除了LinearLayoutManager
外, 还提供了GirdLayoutManager网格布局
和StaggeredGridLayoutManager瀑布流布局
两种内置的布局排列方式.
修改fruit_item的代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp">
<ImageView
android:id="@+id/fruitImage"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp" />
<TextView
android:id="@+id/fruitName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="10dp" />
</LinearLayout>
修改MainActivity
class MainActivity : AppCompatActivity() {
private val fruitList = ArrayList<Fruit>()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
initFruits()
// 3列, 纵向排列
val layoutManager = StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL)
binding.recyclerView.layoutManager = layoutManager
val adapter = FruitAdapter(fruitList)
binding.recyclerView.adapter = adapter
}
private fun initFruits() {
repeat(2) {
fruitList.add(Fruit(getRandomLengthString("Apple"),
R.drawable.apple_pic))
fruitList.add(Fruit(getRandomLengthString("Banana"),
R.drawable.banana_pic))
fruitList.add(Fruit(getRandomLengthString("Orange"),
R.drawable.orange_pic))
fruitList.add(Fruit(getRandomLengthString("Watermelon"),
R.drawable.watermelon_pic))
fruitList.add(Fruit(getRandomLengthString("Pear"),
R.drawable.pear_pic))
fruitList.add(Fruit(getRandomLengthString("Grape"),
R.drawable.grape_pic))
fruitList.add(Fruit(getRandomLengthString("Pineapple"),
R.drawable.pineapple_pic))
fruitList.add(Fruit(getRandomLengthString("Strawberry"),
R.drawable.strawberry_pic))
fruitList.add(Fruit(getRandomLengthString("Cherry"),
R.drawable.cherry_pic))
fruitList.add(Fruit(getRandomLengthString("Mango"),
R.drawable.mango_pic))
}
}
private fun getRandomLengthString(str: String): String {
val n = (1..20).random()
val builder = StringBuilder()
repeat(n) {
builder.append(str)
}
return builder.toString()
}
}
RecyclerView的点击事件
修改FruitAdapter
class FruitAdapter(val fruitList: List<Fruit>): RecyclerView.Adapter<FruitAdapter.ViewHolder>()
{
...
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
...
// itemView表示最外层的布局
viewHolder.itemView.setOnClickListener {
val position = viewHolder.adapterPosition
val fruit = fruitList[position]
Toast.makeText(parent.context, "you clicked view ${fruit.name}", Toast.LENGTH_SHORT).show()
}
viewHolder.fruitImage.setOnClickListener {
val position = viewHolder.adapterPosition
val fruit = fruitList[position]
Toast.makeText(parent.context, "you clicked image ${fruit.name}", Toast.LENGTH_SHORT).show()
}
return viewHolder
}
...
}