Kotlin快速开发(二)

NavHostFragment的使用

  • 在res文件夹下创建新建navigation文件夹在该文件下创建导航图.xml文件
  • 在MainActivity的.xml文件中使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
  <!-- android:name 属性指向 NavHostFragment
 app:navGraph 属性指向navigation 文件夹下的nav_graph文件 -->
    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/nav_graph"
        app:defaultNavHost="true" />

</androidx.constraintlayout.widget.ConstraintLayout>
//----------------------------------------------------------------------
<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"
    android:id="@+id/nav_graph"
    app:startDestination="@id/loginFragment">

    <fragment
        android:id="@+id/loginFragment"
        android:name="com.example.application.LoginFragment"
        android:label="fragment_login"
        tools:layout="@layout/fragment_login" >
        <action 
            android:id="@+id/action_loginFragment_to_friendsFragment"
            app:destination="@id/friendsFragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right"/>
    </fragment>
    <fragment
        android:id="@+id/friendsFragment"
        android:name="com.example.application.FriendsFragment"
        android:label="fragment_friends"
        tools:layout="@layout/fragment_friends" />
</navigation>

navigation标签下可以放多个fragment 可以用线对其连接形成关系可以添加fragment之间传递的参数 也可以添加fragment切换的转场动画等等。。。

例:如果碰到从首页->列表->详情 想从详情直接返回到首页

  • 给列表到详情的action的添加属性popUpto这个id设置后返回会回到popUpto指向的fragment
  • 另一种可以通过代码动态设置
 fun onJump(sesionId: String, sessType: Int) {
                val navOption = NavOpitenHelper.defultAnim(fromBundle.popId)//可以直接写死 也可以是参数传过来
                findNavController().navigate(CaptureFragmentDirections
                    .ActionCaptureFragmentToSearchForMedieFragment(sesionId,sessType),navOption)
            }

 fun defultAnim(popId: Int): NavOptions {
        return NavOptions.Builder() //设置转场动画 和popUpto
            .setEnterAnim(R.anim.slide_in_right) 
            .setExitAnim(R.anim.slide_out_left)
            .setPopEnterAnim(R.anim.slide_in_left)
            .setPopExitAnim(R.anim.slide_out_right)
            .setPopUpTo(popId,false)
            .build()

    }

监听

 findNavController(R.id.myNavHostFragment).addOnDestinationChangedListener{
                _: NavController, navDestination: NavDestination, _: Bundle? ->
          //TODO 具体业务 可以在这里判断正在交互是哪个Fragment  变更状态栏 
        // 沉浸式状态栏 全屏等都可以在这里处理 
        }

//这个可以直接获取正在交互的fagment的Id
val id = findNavController(R.id.myNavHostFragment).currentDestination?.id

ViewModel

这里就介绍一种创建方式

class LoginVM(var app:Application):AndroidViewModel(app) {

}
class LoginVM():ViewModel() {

}
//两种建议用第一种带Application
class LoginVM(var app:Application):AndroidViewModel(app) {

    
    class Factory(val app:Application):ViewModelProvider.Factory{
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            if (modelClass.isAssignableFrom(LoginVM::class.java)) {
                @Suppress("UNCHECKED_CAST")
                return LoginVM(app)as T
            }else{
                throw IllegalAccessException("Unkown ViewModel class")
            }
        }
    }

}

//-----------------------------activity中创建------------------------
class LoginFragment : Fragment() {
    private val viewmodel:LoginVM by lazy {
        val app = requireNotNull(this.activity).application
        ViewModelProvider(this,LoginVM.Factory(app)).get(LoginVM::class.java)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewmodel.login.observe(viewLifecycleOwner, Observer {
            it?.let {
                if (it==1) {
                    findNavController().navigate(LoginFragmentDirections.actionLoginFragmentToFriendsFragment())
                    viewmodel.close()
                }
            }
        })
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val binding: FragmentLoginBinding =
            DataBindingUtil.inflate(inflater, R.layout.fragment_login, container, false)
        binding.lifecycleOwner = this
        binding.viewmodel = viewmodel
        return binding.root
    }

}

在UI布局文件中的使用

<layout
    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">
    <data>
        <variable
            name="viewmodel"
            type="com.example.application.LoginVM" />
    </data>
</layout>
//控件绑定数据 和点击事件 
<TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="50dp"
        android:text="@{viewmodel.title}"
        android:onClick="@{()->viewmodel.login(phone,pwd)}"
        android:contentDescription="@string/hello_blank_fragment"
        app:layout_constraintBottom_toTopOf="@+id/phone"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
//控件绑定数据逻辑处理
<TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="50dp"
        app:bindtitle="@{viewmodel.type}"
        android:contentDescription="@string/hello_blank_fragment"
        app:layout_constraintBottom_toTopOf="@+id/phone"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
//创建一个kotlin文件
@BindingAdapter("bindtitle")
fun bindtitle(titleView: TextView,titleType:Int){
        if(titleType==1){
            titleView.text = "标题1"
        }else{
            titleView.text = "标题2"
        }
}
//这样就完成了数据逻辑的绑定  可以绑定ImageView  和Url 直接用glide 加载出来

RecyclerView的绑定

<?xml version="1.0" encoding="utf-8"?>
<layout 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">
    <data>
        <variable
            name="viewmodel"
            type="com.example.application.FriendsVM" />
    </data>

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FriendsFragment">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvl"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        tools:listitem="@layout/contacts_item"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>


</androidx.constraintlayout.widget.ConstraintLayout>
</layout>


//------------------------activity中-----------------
 private var adaper :FriendsAdapter?=null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewmodel.friendList.observe(viewLifecycleOwner, Observer {
            it?.apply {
                adaper?.setList(it)
            }
        })
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val bindind:FragmentFriendsBinding =
            DataBindingUtil.inflate(inflater,R.layout.fragment_friends, container, false)
        bindind.lifecycleOwner = this
        bindind.viewmodel = viewmodel
        adaper = FriendsAdapter(arrayListOf(),AdapterOnClike{
            Timber.e(it.toString()) //点击事件
        })
        bindind.root.findViewById<RecyclerView>(R.id.rvl).apply {
            adapter = adaper
        }
        return bindind.root
    }

class AdapterOnClike<T>(val block:(T)->Unit){
    fun onClike(t:T) = block(t)
}

class FriendsAdapter(var friends:MutableList<Friend>,val callback:AdapterOnClike<Friend>)
    :BaseQuickAdapter<Friend,BaseDataBindingHolder<ContactsItemBinding>>(R.layout.contacts_item,friends) {
    override fun convert(holder: BaseDataBindingHolder<ContactsItemBinding>, item: Friend) {
       holder.dataBinding.also {
           it?.frinds = item
           it?.friendCallback = callback
       }
    }
}

//---------------item布局文件-------------------
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="frinds"
            type="com.example.application.Friend" />
        <variable
            name="friendCallback"
            type="com.example.application.AdapterOnClike" />
    </data>

<FrameLayout
    android:layout_width="fill_parent"
    android:layout_height="60dp"
    android:onClick="@{()->friendCallback.onClike(frinds)}">

    <ImageView
        android:layout_marginLeft="16dp"
        android:layout_gravity="center_vertical"
        android:id="@+id/contacts_item_head"
        android:layout_width="@dimen/dp_40"
        android:layout_height="@dimen/dp_40"
        app:imageUrl="@{frinds}"
        android:scaleType="centerCrop"/>


    <TextView
        android:id="@+id/contacts_item_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="65dp"
        android:drawablePadding="4dip"
        android:ellipsize="end"
        android:fontFamily="sans-serif-medium"
        android:singleLine="true"
        android:text="@{frinds.displayNick}"
        android:textColor="#333333"
        android:textSize="16sp" />

    <View
        style="@style/horizontal_light_thin_divider"
        android:layout_gravity="bottom"
        android:layout_marginLeft="56dp"/>

</FrameLayout>
</layout>

@BindingAdapter("imageUrl")
fun imageUrl(imageView: ImageView,friend:Friend){
    if (TextUtils.isEmpty(friend.imgHead)) {
        val decodeResource =
            BitmapFactory.decodeResource(imageView.context.resources, R.mipmap.header_bg_5)
        val drawTextToBitmap = drawTextToBitmap(decodeResource, friend.nickName.substring(0,1))
        imageView.setImageBitmap(drawTextToBitmap)
    }else{
        Glide.with(imageView.context).load(friend.imgHead).into(imageView)
    }
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容