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对象)与特定的适配器(委托适配器)相匹配,就像可以在此印象中看到的那样:
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
需要做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
现在我们已经创建了新闻项目,我们需要我们的委托适配器来负责创建视图。
在这里你可以预览我们需要什么:
预览一条新闻
所以我们需要:
显示标题,作者,评论等文字一个图像,我们要使用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) ,IntRange从IntProgression扩展,这实现了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代码开发,但是我希望你从中能学习了新的代码。
此外,我们的代码越来越好(或在列表中显示的东西在用户界面,哈哈)。
不要犹豫,联系我的任何问题,我会尽力给你一个答案。
Twitter:https://twitter.com/juanchosaravia
下一篇预告文章:第5部分:Kotlin,RxJava和RxAndroid混合开发
推荐:
以上是关于Kotlin Part4, RecyclerView 使用Kotlin的适配器模型开发的主要内容,如果未能解决你的问题,请参考以下文章