在UI中显示Forecast list(十一)

第一、
我们希望显示一个图标,日期,描述以及最高和最低温度。所以让我们创建一个名为item_forecast.xml的layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/spacing_xlarge"
    android:background="?attr/selectableItemBackground"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="48dp"
        android:layout_height="48dp"
        tools:src="@mipmap/ic_launcher"/>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_marginLeft="@dimen/spacing_xlarge"
        android:layout_marginRight="@dimen/spacing_xlarge"
        android:orientation="vertical">

    <TextView
        android:id="@+id/date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        tools:text="May 14, 2015"/>

    <TextView
        android:id="@+id/description"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="@style/TextAppearance.AppCompat.Caption"
        tools:text="Light Rain"/>

    </LinearLayout>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="vertical">

    <TextView
        android:id="@+id/maxTemperature"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        tools:text="30"/>

    <TextView
        android:id="@+id/minTemperature"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="@style/TextAppearance.AppCompat.Caption"
        tools:text="15"/>

    </LinearLayout>
</LinearLayout>
Domain model和数据映射时必须生成完整的图标uil,所以我们可以这样去加载它:
data class Forecast(val date: String, val description: String,
                    val high: Int, val low: Int, val iconUrl: String)
在ForecastDataMapper中:
private fun convertForecastItemToDomain(forecast: Forecast): ModelForecast {
    return ModelForecast(convertDate(forecast.dt),
            forecast.weather[0].description, forecast.temp.max.toInt(),
            forecast.temp.min.toInt(), generateIconUrl(forecast.weather[0].icon))
}

private fun generateIconUrl(iconCode: String): String
        = "http://openweathermap.org/img/w/$iconCode.png"
我们从第一个请求中得到图标的code,用来组成完成的图标url。加载图片最简单的方式是使用图片加载库。Picasso是一个很好的类库。它需要加到build.gradle的依赖中:
compile "com.squareup.picasso:picasso:<version>"
如此,Adapter也需要一个大的改动了。还需要一个click listener,我们来定义它:
public interface OnItemClickListener {
     operator fun invoke(forecast: Forecast)
}
通过学习我们知道,当被调用时invoke方法可以被省略。所以我们来使用它来简化。listener可以被以下两种方式调用:
itemClick.invoke(forecast)
itemClick(forecast)
viewHolder将负责去绑定数据到新的View:
class ViewHolder(view: View, val itemClick: OnItemClickListener) :
                RecyclerView.ViewHolder(view) {
    private val iconView: ImageView
    private val dateView: TextView
    private val descriptionView: TextView
    private val maxTemperatureView: TextView
    private val minTemperatureView: TextView

    init {
        iconView = view.find(R.id.icon)
        dateView = view.find(R.id.date)
        descriptionView = view.find(R.id.description)
        maxTemperatureView = view.find(R.id.maxTemperature)
        minTemperatureView = view.find(R.id.minTemperature)
    }

    fun bindForecast(forecast: Forecast) {
        with(forecast) {
            Picasso.with(itemView.ctx).load(iconUrl).into(iconView)
            dateView.text = date
            descriptionView.text = description
            maxTemperatureView.text = "${high.toString()}"
            minTemperatureView.text = "${low.toString()}"
            itemView.setOnClickListener { itemClick(forecast) }
        }
    }
}
现在Adapter的构造方法接收一个itemClick。创建和绑定数据也是更简单:
public class ForecastListAdapter(val weekForecast: ForecastList,
         val itemClick: ForecastListAdapter.OnItemClickListener) :
        RecyclerView.Adapter<ForecastListAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
            ViewHolder {
        val view = LayoutInflater.from(parent.ctx)
            .inflate(R.layout.item_forecast, parent, false)
        return ViewHolder(view, itemClick)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bindForecast(weekForecast[position])
    }
    ...
}
如果你使用了上面这些代码,parent.ctx不会被编译成功。Anko提供了大量的扩展函数来让Android编程更简单。举个例子,activitys、fragments以及其它包含了ctx这个属性,通过ctx这个属性来返回context,但是在View中缺少这个属性。所以我们要创建一个新的名叫ViewExtensions.kt文件来代替ui.utils,然后增加这个扩展属性:
val View.ctx: Context
    get() = context
从现在开始,任何View都可以使用这个属性了。这个不是必须的,因为你可以使用扩展的context属性,但是我觉得如果我们使用ctx的话在其它类中也会更有连贯性。而且,这是一个很好的怎么去使用扩展属性的例子。

最后,MainActivity调用setAdapter,最后结果是这样的:
forecastList.adapter = ForecastListAdapter(result,
        object : ForecastListAdapter.OnItemClickListener{
            override fun invoke(forecast: Forecast) {
                toast(forecast.date)
            }
        })
和java创建一个匿名内部类类似,我们去创建了一个实现了刚刚创建的接口的对象。看起来不是很好,对吧?这是因为我们还没开始试使用另一个强大的函数式编程的特性,在之后的学习中我们会做到把代码写的更加简便易读。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值