Android开发(27)——RecycleView实战:类似网易新闻的浏览页面

本节内容

1.数据模块布局

2.确定数据源

3.设置item

4.监听item点击事件

一、数据模块布局
1.先从containers里面拖动一个RecycleView布局进来,并设置一下id为mRecycler
activity_main.xml
2.在MainActivity里面配置RecyclerView 的样式。第三个参数reverseLayout,要不要反着显示数据,比如说QQ空间,最新也是最后发布的消息一般显示在最前面。但是我们这里不需要反着显示。
 mRecycler.layoutManager = LinearLayoutManager(
                this,
                LinearLayoutManager.VERTICAL,
                false
        )
3.样式搞定之后开始设置适配器(提供具体显示的数据),那么新建一个类来实现Adapter。
class NewsAdapter :RecyclerView.Adapter<NewsAdapter.NewsViewHolder>() {
     inner  class NewsViewHolder(itemView: View) :RecyclerView.ViewHolder(itemView){
      }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder { }
override fun getItemViewType(position: Int): Int {}
override fun getItemCount(): Int {}
override fun onBindViewHolder(holder: NewsViewHolder, position: Int) {}
}
4.因为要向NewsAdapter这个类传递数据,但是如果都交给主类的话,主类的压力就很大。所以我们设置一个中转站仓库,让它来判断数据是来自网络、数据库还是本地。对于中转站来说,只要提供一个加载数据的方法即可。
  • 新建一个名为Repository的类,并设置单例设计模式。
class Repository private constructor(){
    companion object{
        private var instance = Repository()
        fun getInstance() = instance
    }
}
  • 在这个仓库类里面,还要有获取数据的接口和更改数据的接口
private fun loadData(){
}
5.显示新闻的版式有两种,一种左边是标题,右边是图片,下边是点赞数。还有一种上边是标题,下边是图片和点赞数。这三个控件都是分散的,所以我们要把它们封装为一个整体。
所以我们提供一个类,里面包括标题、图片、点赞数。(因为在这里面什么也不做,所以为数据类)
  • 图片和标题都是不可变的,点赞数是可变的。最后一个参数是版面的类型,我们提供的版式有两种,0表示一种,1表示一种。
data class NewsModel(val title:String,
                     val imageId:Int,
                     var like:Int,
                     val type:Int
                     )
6.创建一个接口,在里面提供一个 getData()方法。判断数据是从哪个地方加载的(本地/数据库/网络)返回值为数组。
interface DataInterface {
    fun getData():ArrayList<NewsModel>
}
7.创建一个LocalUtil类,这个类继承自DataInterface ,在这个类里面加载数据。这里我们自己模拟一下,所以自己写一点死的数据。
class LocalUtil :DataInterface{
    override fun getData(): ArrayList<NewsModel> {
        //制造数据
        val d1 = NewsModel("安卓开发",R.drawable.cute2,2021,0)
        val d2 = NewsModel("ios开发",R.drawable.cute1,1193,1)
        val d3 = NewsModel("python开发",R.drawable.cute1,3000,0)
        val d4 = NewsModel("Web开发",R.drawable.cute2,150,1)
        return arrayListOf(d1,d2,d3,d4)
    }
}
二、确定数据源
1.实现Repository类里面的loadData()方法。获取数据之后,我们要将其保存起来。所以我们在实现这个方法之前要先定义一个变量来保存接收的数据。
  • 它是一个可变数据源,所以要私有化,不能让外部轻易访问。然后封装为不可变的提供给外部使用。
private val mdatas = mutableListOf<NewsModel>()
var datas:List<NewsModel> = listOf()
        get() {
        if(field.isEmpty()){
            //如果没有就加载一次,有就直接返回
            loadData()
            field = mdatas.toList()
        }
            return field
    }
2.然后再实现loadData()方法
private fun loadData(){
        //当前通过localUtil获取数据
       val dataSource:DataInterface = LocalUtil()
        //将获取的数据添加到数据源中
       mdatas.addAll( dataSource.getData())
    }
3.在NewsAdapter里面可以实现 getItemCount()方法了。
override fun getItemCount(): Int {
        //访问数据中心获取数据的条数
      return  Repository.getInstance().datas.size
    }
三、设置item
1.在layout里面设置两种xml。直接用约束布局,可以自己任意设置,这个不是重点。我设置的如下图所示。
news_lent.xml

news_port.xml
2.整好之后,我们就需要在NewsAdapter类里面的onCreateViewHolder()方法里面创建一个item,使用LayoutInflater 将xml转化为view。在解析之前,我们要先判断它是哪种类型,所以我们要先写一个方法来设置position对应的那个item类型。
 override fun getItemViewType(position: Int): Int {
        //获取position对应的模型数据
       val model= Repository.getInstance().datas[position]
        return model.type
    }
3.然后就可以在onCreateViewHolder里面解析了。因为我们写了前面那个函数,所以下面这个方法中的参数viewType对应的就是我们前面返回的type。中间的过程系统会自动完成,不用想太多。
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder {
        val lf =  LayoutInflater.from(parent.context)
        val view:View
        //判断当前这个item的类型
        if(viewType == 0){
           view= lf.inflate(R.layout.news_lent,parent,false)
        }else{
           view= lf.inflate(R.layout.news_port,parent,false)
        }
        return NewsViewHolder(view)
    }
4.在NewsViewHolder方法里面,获取每个控件。mTitle是给TextView设置的id,后面两个也一样。
inner  class NewsViewHolder(itemView: View) :RecyclerView.ViewHolder(itemView){
           //从当前view中 获取每个控件
        val titleTextView = itemView.findViewById<TextView>(R.id.mTitle)
        val iconImageView = itemView.findViewById<ImageView>(R.id.mIcon)
        val likeTextView = itemView.findViewById<TextView>(R.id.mLike)
     
    }
5.然后在onBinderView方法里面,把它们都解析出来。
override fun onBindViewHolder(holder: NewsViewHolder, position: Int) {
        //获取position对应的模型数据
        val model = Repository.getInstance().datas[position]
        holder.titleTextView.text = model.title
        holder.iconImageView.setImageResource(model.imageId)
        holder.likeTextView.text = model.like.toString()

        }
    }
6.在MainActivity里面设置一下适配器
mRecycler.adapter = NewsAdapter()
7.然后运行一下,得到如下结果。
结果
  • 出现这种情况,我们只要把约束布局的高度改为wrap_content即可(两个xml的约束布局高度都要改),然后得到了以下结果。这个是可以往下滑动的。
第二个结果
四、监听item点击事件
1.在newsAdapter类里面的onBindViewHolder方法里面,给itemView设置一个点击事件。
 holder.itemView.setOnClickListener{
        }
2.如果在响应点击事件之后需要进行界面跳转,那么要把事件传给MainActivity然后再调用startActivity方法,这两个类之间就存在一个回调。
  • 所以我们先在newsAdaper类里面定义一个回调参数。
var callBack:((Int)->Unit)? = null
  • 然后在init里面进行回调。
   callBack?.let {
                it(position)
            }
3.在MainActivity里面再重新设置一下适配器,并实现回调。
val adapter = NewsAdapter()
        adapter.callBack = {
            startActivity(Intent(this,news2::class.java))
        }
        mRecycler.adapter = adapter
  • 之后运行程序,打开之后点击画面,就会进行跳转
4.如果觉得这样很麻烦的话,可以在NewsViewHolder类里面定义一个变量来记录位置
 var mPosition = 0
  • 然后在onBindViewHolder类里面把position赋值给它
 holder.mPosition = position
  • 最后回到NewsViewHolder类里面,设置一下监听器。
init {
           itemView.setOnClickListener{
               callBack?.let {
                   it(mPosition)
               }
           }
       }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容