开始前我们先回答几个问题
1.Jetpack是什么/怎么用?
2.android-sunflower-0.1.6是什么?
问题一:
问题二:
长征第一步
地址:https://github.com/googlesamples/android-sunflower
--------------------------------------进入正题---------------------------------------
//按道理Databinding应该初始化garden_nav_fragment这个类
val navController = Navigation.findNavController(this, R.id.garden_nav_fragment)
//初始化操作
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
// 绑定Menu点击事件
binding.navigationView.setupWithNavController(navController)
// 固定写法,不然抽屉打不开
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(drawerLayout,
Navigation.findNavController(this, R.id.garden_nav_fragment))
}
PS:了解Kotlin中Databinding用法的请参考Kotlin中使用DataBinding的简单实现
//这个是必须存在的
<fragment
android:id="@+id/garden_nav_fragment"
//固定写法
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
//重写返回键
app:defaultNavHost="true"
//定位到nav_garden 注意文件夹名字
app:navGraph="@navigation/nav_garden" />
*可以发现页面跳转全部是Fragment了,这个就是NavigationUI的精髓*
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
//默认显示的第一个Fragment(花园)
app:startDestination="@+id/garden_fragment">
//花园
<fragment
android:id="@+id/garden_fragment"
//对应类名
android:name="com.google.samples.apps.sunflower.GardenFragment"
android:label="@string/my_garden_title"
//布局
tools:layout="@layout/fragment_garden" />
//植物列表
<fragment
android:id="@+id/plant_list_fragment"
android:name="com.google.samples.apps.sunflower.PlantListFragment"
android:label="@string/plant_list_title"
tools:layout="@layout/fragment_plant_list">
//action写好了 如何触发到植物详情的呢?
<action
android:id="@+id/action_plant_list_fragment_to_plant_detail_fragment"
app:destination="@id/plant_detail_fragment" />
</fragment>
//植物详情
<fragment
android:id="@+id/plant_detail_fragment"
android:name="com.google.samples.apps.sunflower.PlantDetailFragment"
android:label="@string/plant_details_title"
tools:layout="@layout/fragment_plant_detail">
<argument
android:name="plantId"
app:argType="string" />
</fragment>
</navigation>
<action
//这个ID一看就自动生成的
android:id="@+id/action_plant_list_fragment_to_plant_detail_fragment"
app:destination="@id/plant_detail_fragment" />
命名规则:很好理解
action_XXX_to_XXX
里面的ViewModelProviders是控制生命周期用的后面讲
//显示Menu菜单 说实话国内很少用menu
setHasOptionsMenu(true)
//Databinding在RecyclerView上的应用,确实方便了许多,不过也增大了阅读的难度
val adapter = PlantAdapter()
binding.plantList.adapter = adapter
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val plant = getItem(position)
holder.apply {
//将createOnClickListener函数当参数传递的sao操作
bind(createOnClickListener(plant.plantId), plant)
itemView.tag = plant
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
//ListItemPlantBinding 对应布局 tools:listitem="@layout/list_item_plant"
return ViewHolder(ListItemPlantBinding.inflate(
LayoutInflater.from(parent.context), parent, false))
}
private fun createOnClickListener(plantId: String): View.OnClickListener {
//写法比较复杂,就是为了实现一个点击跳转事件,
return View.OnClickListener {
//这个ActionPlantListFragmentToPlantDetailFragment应该是Navigation专属编译类
//理解为Intent
val direction = PlantListFragmentDirections.ActionPlantListFragmentToPlantDetailFragment(plantId)
//对应下面的扩展函数
//理解为startActivity
it.findNavController().navigate(direction)
}
}
class ViewHolder(
private val binding: ListItemPlantBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(listener: View.OnClickListener, item: Plant) {
binding.apply {
clickListener = listener
plant = item
//1.更新视图
//2.be run on the UI thread.
executePendingBindings()
}
}
}
//扩展函数View.kt
fun View.findNavController(): NavController =
Navigation.findNavController(this)
PS:植物列表->植物详情操作:就是通过 it.findNavController().navigate(direction)完成的
对应nav_garden中的
<argument
android:name="plantId"
app:argType="string" />
databinding自定义属性
@BindingAdapter("wateringText")
fun bindWateringText(textView: TextView, wateringInterval: Int) {
val resources = textView.context.resources
val quantityString = resources.getQuantityString(R.plurals.watering_needs_suffix,
wateringInterval, wateringInterval)
textView.text = SpannableStringBuilder()
.bold { append(resources.getString(R.string.watering_needs_prefix)) }
.append(" ")
.italic { append(quantityString) }
}
对应
app:wateringText="@{viewModel.plant.wateringInterval}"
预览可见:新特性,比较有用
tools:text="Watering needs: every 7 days"
新分享
val shareIntent = ShareCompat.IntentBuilder.from(activity)
.setText(shareText)
.setType("text/plain")
.createChooserIntent()
.apply {
// https://android-developers.googleblog.com/2012/02/share-with-intents.html
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// If we're on Lollipop, we can open the intent as a document
addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
} else {
// Else, we will use the old CLEAR_WHEN_TASK_RESET flag
addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
}
}
startActivity(shareIntent)
import android.app.Fragment
//改成
import androidx.fragment.app.Fragment
val direction = PlantDetailFragmentDirections.ActionPlantDetailFragmentToAboutFragment()
findNavController().navigate(direction)//扩展函数
JetPack控件LifeCycles(基于android-sunflower-0.1.6)