JetPack控件NavigationUI(基于android-sunflower-0.1.6)

前言:

开始前我们先回答几个问题

1.Jetpack是什么/怎么用?
2.android-sunflower-0.1.6是什么?

问题一:

  1. Jetpack是什么?
    *给出下图:*简单的概括为四大组件库,可以看到他提供的功能还是蛮实用的,没有多余的部分。
    是什么
  2. Jetpack怎么用?
    这个问题比较大一下说不清楚,我们从接下来的源码分析中,一步一步理解和掌握,有人会说既然做这么多年开发直接看文档不就能行了吗,你说的有道理,但是阅读外文文档学习确实不符合中国国情,这里就涉及到个人以及政治方面的原因了。也可以看到上面的模块之多,不是一日而语的,纸上读来终觉浅,绝知此事要躬行,我们需要慢慢来,我也是第一次在技术迁移上感受到这种焦虑感,Kotlin在Android开发当中的比重越来越大,还在使用JAVA的伙伴赶紧跟上脚步。

问题二:
长征第一步
地址:https://github.com/googlesamples/android-sunflower
--------------------------------------进入正题---------------------------------------

NavigationUI

坐标:GardenActivity
//按道理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的简单实现

坐标:activity_garden
//这个是必须存在的 
 <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" />

nav

坐标: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>

跳转实现

  1. 花园 -> 植物列表:切换时通过Menu绑定ID实现的。
  2. 植物列表 -> 植物详情:
<action
//这个ID一看就自动生成的
     android:id="@+id/action_plant_list_fragment_to_plant_detail_fragment"
     app:destination="@id/plant_detail_fragment" />

命名规则:很好理解

action_XXX_to_XXX
坐标:PlantListFragment

里面的ViewModelProviders是控制生命周期用的后面讲

//显示Menu菜单 说实话国内很少用menu
 setHasOptionsMenu(true)
//Databinding在RecyclerView上的应用,确实方便了许多,不过也增大了阅读的难度
val adapter = PlantAdapter()
binding.plantList.adapter = adapter
坐标:PlantAdapter
 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" />

可以看到编译期自动生成
intent

坐标:PlantDetailFragment

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)

自己来操作一遍

creat_new
create_new2
可以发现这个有个中划线,是因为继承的不对

import android.app.Fragment
//改成
import androidx.fragment.app.Fragment

create_new3
回到nav_garden

新建

新建

拖动

推动

效果

效果
编译一下生成相应的XXXragmentDirections

调用
val direction = PlantDetailFragmentDirections.ActionPlantDetailFragmentToAboutFragment()
findNavController().navigate(direction)//扩展函数

LifeCycles

JetPack控件LifeCycles(基于android-sunflower-0.1.6)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值