63. (android开发)RecyclerView动态加载内容

android开发中RecyclerView现在已经是很常用的一个组件了。可以灵活的布局,运行效率也比ListView要好很多。只不过,它不是天然支持的,需要在app/build.gradle文件中添加包的引用
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() 就是获取当前时间的一个自定义函数。你可以换成别的东西来实现。和本文要讲的重点无关。

看一下界面最终效果
RecyclerView动态加载内容效果

关于数据从服务器上获取,相信通过前面的几节内容就可以很容易实现对本节中相应内容做更新了。
点击和长按操作

如果只是显示,显然还缺少另一个最常见的功能——点击。既然有点击,作为手机操作也有另一个类似的操作——长按。这两个也是要实现一下的。
当然,要点击一定是有数据才有点击的需要,因为要看详情嘛。那么点击监听就在 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
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容