63. (android开发)RecyclerView动态加载内
在项目的主界面需要增加RecyclerView组件。由于这个组件是通过引用加入的,所以在添加的时候要写全路径
<android.support.v7.widget.RecyclerView
android:id="@+id/articleRecycleView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
这是组件的外层,而内部动态显示内容还需要再建一个xml来实现。当然,每一个显示块也就是item的界面结构,就要在这个新建的xml文件里布局了。本demo就做的简单点。新建一个article_item.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="wrap_content"
android:orientation="vertical"
android:background="#98623c">
<TextView
android:id="@+id/article_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/article_item_publish_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:background="#e6cde3"/>
</LinearLayout>
在ide中,现在是看不到效果的。
article_item.xml编辑器预览结果
只能是先写代码了。
在activity中添加代码
先建立一个模拟数据
/**模拟数据*/
private val data:Array<String> = arrayOf("苹果", "香蕉", "桔子", "橙子", "核桃", "西瓜", "水蜜桃", "猕猴桃", "罗汉果", "梨", "菠萝", "殷桃", "葡萄", "草莓", "橄榄", "火龙果", "蛇果", "蓝莓", "牛油果", "山楂", "芒果", "杏", "桃", "哈密瓜", "山竹", "桂圆", "荔枝")
再建立一个界面动态显示数据的保存数组
/**数据显示数组*/
private val articleList = ArrayList<Article>()
针对item里的显示元素,需要一个数据类来构建。
/**文章数据类*/
data class Article( val indexPic: String, //引导图
val title: String, //标题
val subhead: String, //副标题
val author: String, //作者
val publishTime: String //发布时间
)
当activity运行起来的时候,我们首先要做内容的初始化,就是把所有要显示的数据都加载进来。步骤是先把所有数据都放进数据显示数组articleList,然后再把数据都一条条绑定到界面article_item。
数据初始化使用一个initArticles()方法来实现
/**数据初始化,获得要展示的数据,并加载到数据显示数组*/
private fun initArticles() {
articleList.clear() //清理原有数据
for (i in data.indices){
val article = Article("",data[i],"","", getNow())
articleList.add(article)
}
}
然后在onCreate中调用。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_articles)
title = "recyclerview"
initArticles() //初始化文章列表数据
val linearLayoutManager = LinearLayoutManager(this)
articleRecycleView.layoutManager = linearLayoutManager
val articleAdapter = ArticleAdapter(this, articleList)
articleRecycleView.adapter = articleAdapter
}
可以看到,在“初始化文章列表数据”之后,就是对界面的管理和数据的绑定了。界面采用了LinearLayoutManager实现管理,而数据采用了Adapter。这里需要我们实现一个ArticleAdapter类。它继承自RecyclerView.Adapter
class ArticleAdapter : RecyclerView.Adapter<ArticleAdapter.ViewHolder>{
private var context:Context? = null
private var articleList:ArrayList<Article>? = null
constructor(context: Context, articleList: ArrayList<Article>){
this.context = context
this.articleList = articleList
}
class ViewHolder:RecyclerView.ViewHolder{
var txtvwTitle: TextView
var txtvwPublishTime: TextView
constructor(itemView: View):super(itemView){
txtvwTitle = itemView.findViewById(R.id.article_item_title)
txtvwPublishTime = itemView.findViewById(R.id.article_item_publish_time)
}
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
if (position < articleList?.size as Int){
val article = articleList?.get(position) //取得当前文章的数据
//--开始赋值
holder?.txtvwTitle?.text = article?.title
holder?.txtvwPublishTime?.text = article?.publishTime
//--结束赋值
}
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent?.context).inflate(R.layout.article_item, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return articleList?.size as Int
}
}
在类中,需要传入上下文和数据,所以在类的构造器上以这两个为参数。
constructor(context: Context, articleList: ArrayList<Article>)
在 ViewHolder 类中,是对界面组件的实例化。以便在类中给指定的组件绑定数据。而绑定数据是在 onBindViewHolder 中实现。
完整代码展示
package com.cofox.functions.Articles
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.cofox.mykt.function.getNow
import com.cofox.mykt.myweather.R
import kotlinx.android.synthetic.main.activity_articles.*
class ArticlesActivity : AppCompatActivity() {
/**模拟数据*/
private val data:Array<String> = arrayOf("苹果", "香蕉", "桔子", "橙子", "核桃", "西瓜", "水蜜桃", "猕猴桃", "罗汉果", "梨", "菠萝", "殷桃", "葡萄", "草莓", "橄榄", "火龙果", "蛇果", "蓝莓", "牛油果", "山楂", "芒果", "杏", "桃", "哈密瓜", "山竹", "桂圆", "荔枝")
/**数据显示数组*/
private val articleList = ArrayList<Article>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_articles)
title = "recyclerview"
initArticles() //初始化文章列表数据
val linearLayoutManager = LinearLayoutManager(this)
articleRecycleView.layoutManager = linearLayoutManager
val articleAdapter = ArticleAdapter(this, articleList)
articleRecycleView.adapter = articleAdapter
}
/**数据初始化,获得要展示的数据,并加载到数据显示数组*/
private fun initArticles() {
articleList.clear() //清理原有数据
for (i in data.indices){
val article = Article("",data[i],"","", getNow())
articleList.add(article)
}
}
}
/**文章数据类*/
data class Article( val indexPic: String, //引导图
val title: String, //标题
val subhead: String, //副标题
val author: String, //作者
val publishTime: String //发布时间
)
class ArticleAdapter : RecyclerView.Adapter<ArticleAdapter.ViewHolder>{
private var context:Context? = null
private var articleList:ArrayList<Article>? = null
constructor(context: Context, articleList: ArrayList<Article>){
this.context = context
this.articleList = articleList
}
class ViewHolder:RecyclerView.ViewHolder{
var txtvwTitle: TextView
var txtvwPublishTime: TextView
constructor(itemView: View):super(itemView){
txtvwTitle = itemView.findViewById(R.id.article_item_title)
txtvwPublishTime = itemView.findViewById(R.id.article_item_publish_time)
}
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
if (position < articleList?.size as Int){
val article = articleList?.get(position) //取得当前文章的数据
//--开始赋值
holder?.txtvwTitle?.text = article?.title
holder?.txtvwPublishTime?.text = article?.publishTime
//--结束赋值
}
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent?.context).inflate(R.layout.article_item, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return articleList?.size as Int
}
}
getNow() 就是获取当前时间的一个自定义函数。你可以换成别的东西来实现。和本文要讲的重点无关。
关于数据从服务器上获取,相信通过前面的几节内容就可以很容易实现对本节中相应内容做更新了。
点击和长按操作
如果只是显示,显然还缺少另一个最常见的功能——点击。既然有点击,作为手机操作也有另一个类似的操作——长按。这两个也是要实现一下的。
当然,要点击一定是有数据才有点击的需要,因为要看详情嘛。那么点击监听就在 articleAdapter 声明之后开始加代码。修改 onCreate 中的相应代码。
val articleAdapter = ArticleAdapter(this, articleList)
articleAdapter.setOnItemClickListener(object : ArticleAdapter.OnItemClickListener {
override fun onClick(position: Int) {
Toast.makeText(this@ArticlesActivity, "onClick点击,第" + position + "个Item被点击了。"+articleList[position].title, Toast.LENGTH_LONG).show()
}
override fun onLongClick(position: Int) {
Toast.makeText(this@ArticlesActivity, "onLongClick长按,第" + position + "个Item被点击了。", Toast.LENGTH_LONG).show()
}
})
articleRecycleView.adapter = articleAdapter
现在执行是没有结果的,还需要在 ArticleAdapter 类中增加相关接口和操作。
在类内部声明一个Item事件监听接口,并建立一个监听的变量及监听操作动作。
//Item事件监听
interface OnItemClickListener {
fun onClick(position: Int)
fun onLongClick(position: Int)
}
private var mOnItemClickListener: OnItemClickListener? = null
fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
this.mOnItemClickListener = onItemClickListener
}
再把监听绑定到每条记录上。
//--开始绑定点击事件
if (mOnItemClickListener != null) {
holder?.itemView?.setOnClickListener { mOnItemClickListener?.onClick(position) }
holder?.itemView?.setOnLongClickListener {
mOnItemClickListener?.onLongClick(position)
false
}
// holder?.txtvwTitle!!.setOnClickListener { mOnItemClickListener?.onClick(position) }
}
//--结束绑定点击事件
这个绑定可以绑定到整个 View ,也可以绑定到 View 内的任一组件上,比如
holder?.txtvwTitle!!.setOnClickListener { mOnItemClickListener?.onClick(position) }
这样就把点击动作绑定到文章标题上了。
运行效果如下
点击
长按
修改后的完整代码
package com.cofox.functions.Articles
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import com.cofox.functions.RecyclerViewJava.FruitAdapter
import com.cofox.mykt.function.getNow
import com.cofox.mykt.myweather.R
import kotlinx.android.synthetic.main.activity_articles.*
class ArticlesActivity : AppCompatActivity() {
/**模拟数据*/
private val data:Array<String> = arrayOf("苹果", "香蕉", "桔子", "橙子", "核桃", "西瓜", "水蜜桃", "猕猴桃", "罗汉果", "梨", "菠萝", "殷桃", "葡萄", "草莓", "橄榄", "火龙果", "蛇果", "蓝莓", "牛油果", "山楂", "芒果", "杏", "桃", "哈密瓜", "山竹", "桂圆", "荔枝")
/**数据显示数组*/
private val articleList = ArrayList<Article>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_articles)
title = "recyclerview"
initArticles() //初始化文章列表数据
val linearLayoutManager = LinearLayoutManager(this)
articleRecycleView.layoutManager = linearLayoutManager
val articleAdapter = ArticleAdapter(this, articleList)
articleAdapter.setOnItemClickListener(object : ArticleAdapter.OnItemClickListener {
override fun onClick(position: Int) {
Toast.makeText(this@ArticlesActivity, "onClick点击,第" + position + "个Item被点击了。"+articleList[position].title, Toast.LENGTH_LONG).show()
}
override fun onLongClick(position: Int) {
Toast.makeText(this@ArticlesActivity, "onLongClick长按,第" + position + "个Item被点击了。", Toast.LENGTH_LONG).show()
}
})
articleRecycleView.adapter = articleAdapter
}
/**数据初始化,获得要展示的数据,并加载到数据显示数组*/
private fun initArticles() {
articleList.clear() //清理原有数据
for (i in data.indices){
val article = Article("",data[i],"","", getNow())
articleList.add(article)
}
}
}
/**文章数据类*/
data class Article( val indexPic: String, //引导图
val title: String, //标题
val subhead: String, //副标题
val author: String, //作者
val publishTime: String //发布时间
)
class ArticleAdapter : RecyclerView.Adapter<ArticleAdapter.ViewHolder>{
private var context:Context? = null
private var articleList:ArrayList<Article>? = null
constructor(context: Context, articleList: ArrayList<Article>){
this.context = context
this.articleList = articleList
}
class ViewHolder:RecyclerView.ViewHolder{
var txtvwTitle: TextView
var txtvwPublishTime: TextView
constructor(itemView: View):super(itemView){
txtvwTitle = itemView.findViewById(R.id.article_item_title)
txtvwPublishTime = itemView.findViewById(R.id.article_item_publish_time)
}
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
if (position < articleList?.size as Int){
val article = articleList?.get(position) //取得当前文章的数据
//--开始赋值
holder?.txtvwTitle?.text = article?.title
holder?.txtvwPublishTime?.text = article?.publishTime
//--结束赋值
//--开始绑定点击事件
if (mOnItemClickListener != null) {
holder?.itemView?.setOnClickListener { mOnItemClickListener?.onClick(position) }
holder?.itemView?.setOnLongClickListener {
mOnItemClickListener?.onLongClick(position)
false
}
// holder?.txtvwTitle!!.setOnClickListener { mOnItemClickListener?.onClick(position) }
}
//--结束绑定点击事件
}
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent?.context).inflate(R.layout.article_item, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return articleList?.size as Int
}
//Item事件监听
interface OnItemClickListener {
fun onClick(position: Int)
fun onLongClick(position: Int)
}
private var mOnItemClickListener: OnItemClickListener? = null
fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
this.mOnItemClickListener = onItemClickListener
}
}