创建一个详情界面 - 提供一个新的activity

优质
小牛编辑
140浏览
2023-12-01

现在我们准备去创建一个DetailActivity。我们详情activity将会接收一组从主activity传过来的参数:forecast id城市名称。第一个参数将会用来从数据库中请求数据,城市名称用于显示在toolbar上。所以我们首先需要定义一组参数的名字:

  1. public class DetailActivity : AppCompatActivity() {
  2. companion object {
  3. val ID = "DetailActivity:id"
  4. val CITY_NAME = "DetailActivity:cityName"
  5. }
  6. ...
  7. }

onCreate函数中,第一步是去设置content view。UI是非常简单的,但是对于这个app来说是足够了:

  1. <LinearLayout
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:orientation="vertical"
  7. android:paddingBottom="@dimen/activity_vertical_margin"
  8. android:paddingLeft="@dimen/activity_horizontal_margin"
  9. android:paddingRight="@dimen/activity_horizontal_margin"
  10. android:paddingTop="@dimen/activity_vertical_margin">
  11. <LinearLayout
  12. android:layout_width="match_parent"
  13. android:layout_height="wrap_content"
  14. android:orientation="horizontal"
  15. android:gravity="center_vertical"
  16. tools:ignore="UseCompoundDrawables">
  17. <ImageView
  18. android:id="@+id/icon"
  19. android:layout_width="64dp"
  20. android:layout_height="64dp"
  21. tools:src="@mipmap/ic_launcher"
  22. tools:ignore="ContentDescription"/>
  23. <TextView
  24. android:id="@+id/weatherDescription"
  25. android:layout_width="wrap_content"
  26. android:layout_height="wrap_content"
  27. android:layout_margin="@dimen/spacing_xlarge"
  28. android:textAppearance="@style/TextAppearance.AppCompat.Display1"
  29. tools:text="Few clouds"/>
  30. </LinearLayout>
  31. <LinearLayout
  32. android:layout_width="match_parent"
  33. android:layout_height="wrap_content">
  34. <TextView
  35. android:id="@+id/maxTemperature"
  36. android:layout_width="0dp"
  37. android:layout_height="wrap_content"
  38. android:layout_weight="1"
  39. android:layout_margin="@dimen/spacing_xlarge"
  40. android:gravity="center_horizontal"
  41. android:textAppearance="@style/TextAppearance.AppCompat.Display3"
  42. tools:text="30"/>
  43. <TextView
  44. android:id="@+id/minTemperature"
  45. android:layout_width="0dp"
  46. android:layout_height="wrap_content"
  47. android:layout_weight="1"
  48. android:layout_margin="@dimen/spacing_xlarge"
  49. android:gravity="center_horizontal"
  50. android:textAppearance="@style/TextAppearance.AppCompat.Display3"
  51. tools:text="10"/>
  52. </LinearLayout>
  53. </LinearLayout>

然后在onCreate代码中去设置它。使用城市的名字设置成toolbar的title。intenttitle通过下面的方法被自动影射到属性:

  1. setContentView(R.layout.activity_detail)
  2. title = intent.getStringExtra(CITY_NAME)

onCreate实现的另一部分是调用command。这与我们之前做的非常相似:

  1. async {
  2. val result = RequestDayForecastCommand(intent.getLongExtra(ID, -1)).execute()
  3. uiThread { bindForecast(result) }
  4. }

当结果从数据库中获取之后,bindForecast函数在UI线程中被调用。我们在这个activity中又一次使用了Kotlin Android Extensions插件来实现不使用findViewById来从XML中获取到属性:

  1. import kotlinx.android.synthetic.activity_detail.*
  2. ...
  3. private fun bindForecast(forecast: Forecast) = with(forecast) {
  4. Picasso.with(ctx).load(iconUrl).into(icon)
  5. supportActionBar.subtitle = date.toDateString(DateFormat.FULL)
  6. weatherDescription.text = description
  7. bindWeather(high to maxTemperature, low to minTemperature)
  8. }

这里有一些有趣的地方。比如,我创建了另一个扩展函数来转换一个Long对象到一个用于显示的日期字符串。记住我们在adapter中也使用了,所以明确定义它为一个函数是个不错的实践:

  1. fun Long.toDateString(dateFormat: Int = DateFormat.MEDIUM): String {
  2. val df = DateFormat.getDateInstance(dateFormat, Locale.getDefault())
  3. return df.format(this)
  4. }

我会得到一个date format(或者使用默认的DateFormat.MEDIUM)并转换Long为一个用户可以理解的String

另一个有趣的地方是bindWeather函数。它会接收一个vararg的由IntTextView组成的pairs,并且根据温度给TextView设置不同的texttext color

  1. private fun bindWeather(vararg views: Pair<Int, TextView>) = views.forEach {
  2. it.second.text = "${it.first.toString()}￿￿"
  3. it.second.textColor = color(when (it.first) {
  4. in -50..0 -> android.R.color.holo_red_dark
  5. in 0..15 -> android.R.color.holo_orange_dark
  6. else -> android.R.color.holo_green_dark
  7. })
  8. }

每一个pair,它会设置一个text来显示温度和一个根据温度匹配的不同的颜色:低温度用红色,中温度用橙色,其它用绿色。温度值是比较随机的,但是这个是使用when表达式让代码变得简短精炼的很好的代表。

color是我想念的Anko中的一个扩展函数,它可以很简洁的方式从resources中获取一个color,类似于我们在其它地方使用到的dimen。我们写下这一行的时候,当前support library依赖ContextCompat来从不同的Android版本中获取一个color:

  1. public fun Context.color(res: Int): Int = ContextCompat.getColor(this, res)

AndroidManifest也需要知道新activity的存在:

  1. <activity
  2. android:name=".ui.activities.DetailActivity"
  3. android:parentActivityName=".ui.activities.MainActivity" >
  4. <meta-data
  5. android:name="android.support.PARENT_ACTIVITY"
  6. android:value="com.antonioleiva.weatherapp.ui.activities.MainActivity" />
  7. </activity>