Kotlin Part4, RecyclerView 使用Kotlin的适配器模型开发

Posted KotlinPython

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin Part4, RecyclerView 使用Kotlin的适配器模型开发相关的知识,希望对你有一定的参考价值。


如果这是你第一次阅读本教程,请阅读第一篇,以了解本教程将要开发的内容。



介绍

在第四部分中,我们将介绍关于Kotlin的这些内容:


  • Init构造函数

  • 对象表达式

  • 单一的表达式

  • 数据类

  • 范围

  • List&Lambdas(介绍)


每个内容将在创建我们的NewsAdapter适配器和使用适配器中说明。

所以让我们开始创建我们的适配器,并在手机屏幕上显示一些东西!


创建NewsAdapter


我们将为我们的RecyclerView创建一个新的适配器。

在这种情况下,我们将使用名为“Delegate Adapter”的模式进行操作,我们将在公司中使用它,灵感来自Hannes Dorfmann撰写的 这篇文章启发



我们的适配器将构建一个Delegate Adapter的列表,将负责如何扩展并在RecyclerView中构造一个特定的View。这需求之后, 一般方案是接收一个

ViewType View

列表,并根据此ViewType获取相应的委托适配器来充气和填充该项目的View。

该项目将被用作参数传递给委托适配器,以便该项目可用于为此视图提取特定数据。


这背后的主要思想是将项目(ViewType对象)与特定的适配器(委托适配器)相匹配,就像可以在此印象中看到的那样:


Kotlin Part4, RecyclerView 使用Kotlin的适配器模型开发


ViewType,我们知道我们需要使用哪个适配器来创建该项目的View。

在例子中,这些项目将是一个新闻列表,在列表的最后,我将添加一个加载效果,以提供更多news。

所以我们需要两个适配器,一个用于News,另一个用于装载。


这种方法给你很多的灵活性,以添加新的视图到你的RecyclerView,只需添加一个新的适配器,对应一个新的ViewType.

例如,我们可以添加一个新的ViewType for Promotions和相应的Delegate Adapter来通过来扩大视图。


继续学习更多需要完成的类和接口。


ViewType


这是一个接口,我们将用于我们要在RecyclerView中显示的项目。

每个项目必须实现这个接口,所以我们可以要求每个项目的ViewType类型(int值),并搜索相应的委托适配器到这种类型:


interface ViewType {
    fun getViewType(): Int
}


在我们的适配器中,我们将有一个名为items的ViewType列表:


private var items:ArrayList <ViewType>


这里我们要存储新闻和加载项目。

我们的NewModel 将从ViewType中扩展,我们将在本地为加载数据是创建一个新项目。


添加一个Loader到我们的RecyclerView

Kotlin Part4, RecyclerView 使用Kotlin的适配器模型开发


需要做3件事情:


  • 该ViewType类型:这将是一个整数值(比如一个ID)给我们ViewType与委托适配器(符合

  • AdapterConstants

    LOADING)。


  • ViewType 的View:这将是实现ViewType接口并返回ViewType类型(ID)的对象。这将允许我们将这个项目插入到项目列表中,并告诉适配器呈现这个视图。

  • 该加载适配器:这将是负责装载的任务,并返回给我们NewsAdapter。


加载适配器的Impl

class LoadingDelegateAdapter : ViewTypeDelegateAdapter {

    override fun onCreateViewHolder(parent: ViewGroup) = TurnsViewHolder(parent)

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) {
    }

    class TurnsViewHolder(parent: ViewGroup) : RecyclerView.ViewHolder(
            parent.inflate(R.layout.news_item_loading)) {
    }
}


正如您所看到的,我们通过扩展另一个名为“ViewTypeDelegateAdapter”的接口来创建适配器。

这个接口允许我们有一个委托适配器的通用列表,并调用这些方法,而不需要我们的NewsAdapter中不知道委托适配器实现的具体内容。一种方法来创建ViewHolder和另一种绑定它。


绑定ViewType类型与代理适配器


我们将使用一个映射为了绑定一个ViewType类型与一个委托适配器(这将在NewsAdapter类中)

private var delegateAdapters = SparseArrayCompat<ViewTypeDelegateAdapter>()init {
    delegateAdapters.put(AdapterConstants.LOADING, LoadingDelegateAdapter())
    ...
}

Init构造函数


init

是Kotlin中类的构造函数(本例中为NewsAdapter)中的保留字,在此我们将初始化此映射,并将每个ViewType类型与相应的委托适配器相加。

在这种情况下:


AdapterConstants.LOADING> LoadingDelegateAdapter()


为了在Kotlin中创建一个新的对象,你不需要使用“new”关键字。

加载ViewType


让我们创建我们的加载项目,这个项目将帮助我们在我们插入到

项目列表中的位置渲染加载视图

private val loadingItem = object:ViewType { 
    override fun getViewType():Int { 
        return AdapterConstants。LOADING
     } 
}


另外默认添加这个项目作为第一个在列表中呈现的项目:


init { 
    delegateAdapters.put(...)
    items = ArrayList()
    items .add(loadingItem)
}

对象表达式

在Kotlin中,你有一种叫做“对象表达式”的东西,它和Java中的匿名内部类相似,并且允许你创建一个对象,而不需要为它明确声明一个新的子类。

在这种情况下,我们正在使用它来定义我们的loadItem而不创建一个新的类。

语法非常直观,您可以看到我们正在从ViewType进行扩展并实现所需的接口。


单一的表达式


getViewType()方法 在主体内只有一个

表达式函数。


在Kotlin中,我们可以利用这一点并转换此方法:


private val loadingItem = object : ViewType {
    override fun getViewType() : Int {
        return AdapterConstants.LOADING
    }
}


这就像我们正在分配AdapterConstants.LOADING值到一个函数。

这是做同样的一个简短的方法,它更简洁。

你也不需要指定返回值类型,因为它可以通过上下文来推断。

所以这就是现在的样子:


private val loadingItem = object:ViewType { 
    override fun getViewType()= AdapterConstants。LOADING
 }


Commit地址


所有这些代码可以在这个提交中找到:



https://github.com/juanchosaravia/KedditBySteps/commit/ecc2546b5a0001149f9fe0ca3295d31ecd9ac542


正如代理适配器的概念所解释的那样,我不打算继续解释每一个细节,而是在本教程的其余部分关注Kotlin概念。

News Item 

在创建新闻委托适配器并配置NewsAdapter以接收新闻列表之前,我们需要我们的UI对象来表示每个新闻。

在Java中,我们通常会创建一个像这样的类:


public class RedditNewsItem {

    private String author;
    private String title;

    public MyNews(String author, String title) {
        this.author = author;
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}


再一次,Kotlin来帮助我们一个叫做“data class”的新类型,它给你带来很多好处,对于同样的例子,它看起来像这样:


data class RedditNewsItem(var author: String, var title: String)


通过这个简单的代码,你可以像前面的Java代码一样执行,这意味着作者和标题有自己的getter和setter,它需要一个带有这两个元素的构造函数。

这只是惊人的!

但是 还是要等等!

如果你参加这个系列课,你仍然可以获得更多的东西,免费可以免费获得此课程:


  • equals / hashCode

  • toString()包含所有的属性。

  • copy()方法来轻松制作对象的副本。

  • 和其他有用的方法,我们不会看到这里,但你可以看到更多的


    官方网页


提交:创建数据类


https://github.com/juanchosaravia/KedditBySteps/commit/3c200af22879e3ec16aaa963ca38ec7e97659971

此外,我们需要让我们的类扩展ViewType,以便它可以作为另一个项目包含在NewsAdapter列表中,在这种情况下作为News项目:



https://github.com/juanchosaravia/KedditBySteps/commit/8b7842c0e2dd9e6496ed55b927183344de4ad771


创建NewsDelegateAdapter


现在我们已经创建了新闻项目,我们需要我们的委托适配器来负责创建视图。

在这里你可以预览我们需要什么:


Kotlin Part4, RecyclerView 使用Kotlin的适配器模型开发

预览一条新闻


所以我们需要:


  • 显示标题,作者,评论等文字一个图像,我们要使用Picasso

(参见下面提交的build.gradle文件)


  • 扩展功能以这种方式显示时间。


在这里,已经添加了所有的代码来创建NewsDelegateAdapter,因为我们不打算抛出每个细节:



https://github.com/juanchosaravia/KedditBySteps/commit/6243623afeb1990a9d98488ee3ffc5623bc9fa61


让我们回顾一下Kotlin的东西:


Picasso的扩展

允许我使ImageView直接加载它的图像:

fun ImageView.loadImg(imageUrl: String) {
    if (TextUtils.isEmpty(imageUrl)) {
        Picasso.with(context).load(R.mipmap.ic_launcher).into(this)
    } else {
        Picasso.with(context).load(imageUrl).into(this)
    }
}

时间扩展

我们将从Reddit接收长格式的评论时间,因此我们在这里做的是将一个Long类型转换为“ 

3天1分钟前”格式的字符串:

import kotlinx.android.synthetic.main.news_item.view.*


检出名为“TimeExt.kt”的文件以查看代码。

当然,这可以改善,但为了这个例子的目的,这是完美的:)


新闻View的Android扩展


检出文件“NewsDelegateAdapter.kt”,你会看到我们也在使用这个视图的Android扩展(就像我们对NewsFragment所做的那样),但是在这种情况下,我们在合成包中增加了一个额外的值,名为“ view”布局名称的结尾:


import kotlinx.android.synthetic.main.news_item.qury*


这是Android扩展允许您仍然将视图与代码绑定而不在Activity或Fragment(如本例中)的上下文中的方式。


更新NewsAdapter以显示新闻


让我们修改我们的NewsAdapter来接收一个模拟News的列表,以显示我们的新闻和加载适配器数据:


Commit


https://github.com/juanchosaravia/KedditBySteps/commit/205258e841d4cc2203cfbcc3e33165fa8a105dce


范围

Kotlin允许你通过一个简单的方式创建一个数字范围(Int,Long和Char类型):“1..10”,这将返回一个IntRange(因为我们在这个例子中使用了Ints) ,IntRangeIntProgression扩展,这实现了Iterable


由于这是我们可以遍历我们有的范围,在这种情况下从1到10 

创建我们的模拟数据:

for(i in 1..10){ 
    ... 
}


您可以控制范围内的步骤,并使其递减为“10 downTo 1”。


更多关于这个,你可以在这里找到它(https://kotlinlang.org/docs/reference/ranges.html)


mutableListOf


这是一个Kotlin函数,它返回一个MutableList,一个可以被修改的列表,在这个例子中是在本地存储适配器的模拟消息:


val news = mutableListOf <RedditNewsItem>()


列出函数和Lambda

我创建了一个方法,稍后我将使用它来保存新闻,当我们处于Orientation Change事件的中间时,但是我想告诉你如何使用list来过滤和映射(转换)每个项目从一个列表到另一个列表。


在我们的代码中,我们有一个名为“getNews”的方法,它返回RedditNewsItems列表。

为了过滤和转换我们的项目(一个ViewType列表),我们要做到这一点:


fun getNews(): List<RedditNewsItem> {
    return items
            .filter { it.getViewType() == AdapterConstants.NEWS }
            .map { it as RedditNewsItem }
}


过滤Filter

每个列表都有一些有用的功能,比如“过滤器Map”,在这种情况下,我们可以迭代列表并过滤(排除)不适用某些条件的项目。


Lambdas

列表中,我们有ViewTypes,所以我们可以有新闻项目或加载项目,使用这个过滤器功能,我们确保只返回那些新闻项目。

Map

另一个很棒的功能是“map”来转换列表中的项目。


在这种情况下,我们将一个ViewType对象转换为RedditNewsItem,但是我们也可以创建并返回新的对象。


Lambda表达式

.map { it as RedditNewsItem }


Map并不是另一个认为接收函数作为第一个参数的函数,但Kotlin使它变得很好,因为它允许排除括号并在函数名称旁边定义一个代码块,最后这个代码块将成为第一个参数该函数所需的代码块是着名的Lambda表达式,这是一个没有声明但是作为表达式立即传递的函数


在这里,我们不打算去详细了解List和Lambdas,但是我认为这是一个很好的起点,可以看到如何使用这个强大的功能。

在本教程的后面,我们将花更多的时间来讨论这个问题。


结语

我知道我花了更多的时间来解释代理适配器模式,而不是Kotlin特有的功能,但是肯定的是,我认为这种模式确实是一个非常优秀的模式,值得使用Kotlin代码开发,但是我希望你从中能学习了新的代码。

此外,我们的代码越来越好(或在列表中显示的东西在用户界面,哈哈)。


不要犹豫,联系我的任何问题,我会尽力给你一个答案。

Twitterhttps//twitter.com/juanchosaravia


下一篇预告文章:第5部分:Kotlin,RxJava和RxAndroid混合开发

推荐:




以上是关于Kotlin Part4, RecyclerView 使用Kotlin的适配器模型开发的主要内容,如果未能解决你的问题,请参考以下文章

面向对象Part4

SQL Server 2012安装配置(Part4 )

UI整理-----part4--UIScrollView

第四周练习 part4

django入门-part4

UML part4 顺序图协作图