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() {
     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
}
7.创建一个LocalUtil类,这个类继承自DataInterface ,在这个类里面加载数据。这里我们自己模拟一下,所以自己写一点死的数据。
class LocalUtil :DataInterface{
    override fun getData(): ArrayList {
        //制造数据
        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()
var datas:List = 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(R.id.mTitle)
        val iconImageView = itemView.findViewById(R.id.mIcon)
        val likeTextView = itemView.findViewById(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)
               }
           }
       }

你可能感兴趣的:(Android开发(27)——RecycleView实战:类似网易新闻的浏览页面)