kotlin - 2个Fragment实现左右显示,左边列表,右边详情,平板横、竖屏切换(一)
kotlin -2个Fragment实现左右显示左边列表右边详情平板横、竖屏切换(要使用平板测试)平板横屏左右fragment实现分屏效果平板竖屏只显示左边的fragment点击才显示右边fragment屏幕旋转会销毁重新创建执行onCreate方法。在AndroidManifest.xml配置android:configChangesscreenSize|smallestScreenSize|screenLayout|orientation|keyboardHidden|navigation属性,只调用onConfigurationChanged方法fragment的add方法如果新打开一个activity该fragment只回调onStop()方法没有调用onDestroy()方法。如果popBackStack或者finish会回调onStop()和onDestroy()方法replace方法旧的fragment执行onDestroy()方法然后新建一个fragment执行onViewCreated()方法。package com.example.androidkotlindemo2.pad.leftright import android.content.Intent import android.content.res.Configuration import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.example.androidkotlindemo2.R import com.example.androidkotlindemo2.utils.LogUtils /** * Author : wn * Email : maoning20080809163.com * Date : 2025/8/30 21:41 * Description : (要使用平板测试)平板横屏左右fragment实现分屏效果平板竖屏只显示左边的fragment点击才显示右边fragment * 屏幕旋转会销毁重新创建执行onCreate方法。 * 在AndroidManifest.xml配置android:configChangesscreenSize|smallestScreenSize|screenLayout|orientation|keyboardHidden|navigation属性,只调用onConfigurationChanged方法 * fragment的 * add方法 * 如果新打开一个activity该fragment只回调onStop()方法没有调用onDestroy()方法。 * 如果popBackStack或者finish会回调onStop()和onDestroy()方法 * replace旧的fragment执行onDestroy()方法然后新建一个fragment执行onViewCreated()方法。 */ classLRFragmentActivity: AppCompatActivity() { //平板横屏 private var isLandscape: Boolean false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.lr_fragment_main) LogUtils.d(LeftRightMainActivity onCreate); // 初始化显示列表Fragment if (savedInstanceState null) { supportFragmentManager.beginTransaction() .replace(R.id.fragment_list_container, LRListFragment()) .commit() } checkOrientation() } //检查横、竖屏 private fun checkOrientation() { val orientation resources.configuration.orientation isLandscape orientation Configuration.ORIENTATION_LANDSCAPE } fun setOnItemClick(position: Int, lrItem: LRItem) { if(position 3){if(isLandscape){ //平板横屏左右显示fragment showItemDetailReplace(lrItem) } else { //平板竖屏使用新的Activity显示 startRightActivity(lrItem) }} else if(position 6){ //只适配平板横屏效果 showItemDetailAdd(lrItem) } else { showItemNewActivity(lrItem) } } //竖屏打开新的Activity fun startRightActivity(lrItem: LRItem){ val intent Intent(this, LRRightActivity::class.java) intent.putExtra(lr_item, lrItem) startActivity(intent) } //使用replace方法 fun showItemDetailReplace(lrItem: LRItem) { val detailFragment LRDetailReplaceFragment.newInstance(lrItem) supportFragmentManager.beginTransaction() .replace(R.id.fragment_detail_container, detailFragment) .commit() } //使用add方法, 只回调onStop方法不回调onDestroy方法 fun showItemDetailAdd(LRItem: LRItem) { val detailNewFragment LRDetailAddFragment.newInstance(LRItem) supportFragmentManager.beginTransaction().add(R.id.fragment_detail_container, detailNewFragment) .addToBackStack(detail_new_fragment) // 添加这行才能popBackStack回退.commit() } //屏幕旋转移除fragment fun removeDetailFragment(){ val detailFragment supportFragmentManager.findFragmentById(R.id.fragment_detail_container) if(detailFragment ! null){ supportFragmentManager.beginTransaction() .remove(detailFragment) .commit() } } //使用add方法, 只回调onStop方法不回调onDestroy方法 fun showItemNewActivity(LRItem: LRItem) { startActivity(Intent(this, LRNewActivity::class.java)) } override funonConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) LogUtils.i(LeftRightMainActivity onConfigurationChanged); checkOrientation() removeDetailFragment() } override fun onStop() { super.onStop() LogUtils.d(LeftRightMainActivity onDestroy) } override fun onDestroy() { super.onDestroy() LogUtils.d(LeftRightMainActivity onDestroy) } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) LogUtils.i(LeftRightMainActivity onNewIntent) } }package com.example.androidkotlindemo2.pad.leftright import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.example.androidkotlindemo2.R import com.example.androidkotlindemo2.utils.LogUtils /** * Author : wn * Email : maoning20080809163.com * Date : 2025/8/30 21:41 * Description : */ classLRListFragment: Fragment(){ private lateinit var recyclerView: RecyclerView private lateinit var adapter: LRAdapter private var LRItemList mutableListOfLRItem() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.lr_fragment_item_list, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupRecyclerView(view) loadItems() } private fun setupRecyclerView(view: View) { recyclerView view.findViewById(R.id.recycler_view) adapter LRAdapter(LRItemList, object : LROnItemClickInter{ override fun setOnItemClick(position: Int, lrItem: LRItem) { // 通知Activity显示详情 (activity as? LRFragmentActivity)?.setOnItemClick(position,lrItem) } override fun setOnLongClickListener(position: Int, lrItem: LRItem) { LogUtils.i(长按${position}) } }) recyclerView.layoutManager LinearLayoutManager(requireContext()) recyclerView.adapter adapter recyclerView.addItemDecoration( DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL) ) } private fun loadItems() { for(i in 1 .. 20){ LRItemList.add(LRItem(i, 项目${i}, 这是第${i}个项目的详细描述)) } adapter.notifyDataSetChanged() } }package com.example.androidkotlindemo2.pad.leftright import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.TextView import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import com.example.androidkotlindemo2.MyApp import com.example.androidkotlindemo2.R import com.example.androidkotlindemo2.utils.LogUtils /** * Author : wn * Email : maoning20080809163.com * Date : 2025/8/30 21:45 * Description : 新的详情使用fragment的add方法调用只会调用onStop() */ classLRDetailAddFragment: Fragment() { companion object { private const val ARG_ITEM item fun newInstance(LRItem: LRItem): LRDetailAddFragment { val fragment LRDetailAddFragment() val args Bundle().apply { putParcelable(ARG_ITEM, LRItem) } fragment.arguments args return fragment } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.lr_fragment_item_detail, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) LogUtils.w(LRDetailAddFragment onViewCreated ----------------------------) LogUtils.w(LRDetailAddFragment onViewCreated() ${this}) arguments?.getParcelableLRItem(ARG_ITEM)?.let { item - displayItemDetails(view, item) } view.findViewByIdButton(R.id.lr_item_details_back).visibility View.VISIBLE //返回 view.findViewByIdButton(R.id.lr_item_details_back).setOnClickListener { LogUtils.i(LRDetailNewFragment返回) requireActivity().supportFragmentManager.popBackStack() } view.findViewByIdButton(R.id.lr_item_details_finish).visibility View.VISIBLE //关闭 - view.findViewByIdButton(R.id.lr_item_details_finish).setOnClickListener { LogUtils.i(LRDetailNewFragment关闭) requireActivity().finish() } } override fun onStart() { super.onStart() LogUtils.w(LRDetailAddFragment onStart() ${this}) } override fun onResume() { super.onResume() LogUtils.w(LRDetailAddFragment onResume() ${this}) } override fun onPause() { super.onPause() LogUtils.w(LRDetailAddFragment onPause() ${this}) } override fun onStop() { super.onStop() LogUtils.w(LRDetailAddFragment onStop() ${this}) } override fun onDestroy() { super.onDestroy() LogUtils.w(LRDetailAddFragment onDestroy() ${this}) } private fun displayItemDetails(view: View, LRItem: LRItem) { view.findViewByIdTextView(R.id.title_text_view).text LRItem.title view.findViewByIdTextView(R.id.description_text_view).text 新页面 LRItem.description view.findViewByIdTextView(R.id.description_text_view).setTextColor(ContextCompat.getColor(MyApp.myApp,R.color.blue)) view.findViewByIdTextView(R.id.description_text_view).setTextSize(30f) } }package com.example.androidkotlindemo2.pad.leftright import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.TextView import androidx.fragment.app.Fragment import com.example.androidkotlindemo2.R import com.example.androidkotlindemo2.utils.LogUtils /** * Author : wn * Email : maoning20080809163.com * Date : 2025/8/30 21:45 * Description : 使用replace方法会调用onStop()和onDestroy()方法 */ classLRDetailReplaceFragment: Fragment() { companion object { private const val ARG_ITEM item fun newInstance(LRItem: LRItem): LRDetailReplaceFragment { val fragment LRDetailReplaceFragment() val args Bundle().apply { putParcelable(ARG_ITEM, LRItem) } fragment.arguments args return fragment } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.lr_fragment_item_detail, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) LogUtils.i(LRDetailReplaceFragment onViewCreated ----------------------------) LogUtils.d(LRDetailReplaceFragment onViewCreated() ${this}) arguments?.getParcelableLRItem(ARG_ITEM)?.let { item - displayItemDetails(view, item) } //返回 view.findViewByIdButton(R.id.lr_item_details_back).visibility View.GONE view.findViewByIdButton(R.id.lr_item_details_finish).visibility View.GONE } override fun onStart() { super.onStart() LogUtils.d(LRDetailReplaceFragment onStart() ${this}) } override fun onResume() { super.onResume() LogUtils.d(LRDetailReplaceFragment onResume() ${this}) } override fun onPause() { super.onPause() LogUtils.d(LRDetailReplaceFragment onPause() ${this}) } override fun onStop() { super.onStop() LogUtils.d(LRDetailReplaceFragment onStop() ${this}) } override fun onDestroy() { super.onDestroy() LogUtils.d(LRDetailReplaceFragment onDestroy() ${this}) } private fun displayItemDetails(view: View, LRItem: LRItem) { view.findViewByIdTextView(R.id.title_text_view).text LRItem.title view.findViewByIdTextView(R.id.description_text_view).text LRItem.description } }package com.example.androidkotlindemo2.pad.leftright import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import android.widget.TextView import androidx.cardview.widget.CardView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import com.example.androidkotlindemo2.MyApp import com.example.androidkotlindemo2.R /** * Author : wn * Email : maoning20080809163.com * Date : 2025/8/30 21:42 * Description : */ classLRAdapter( private val itemList: ListLRItem, private val listener: LROnItemClickInter ) : RecyclerView.AdapterLRAdapter.ItemViewHolder() { var selectedPosition -1 inner class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val titleTextView: TextView itemView.findViewById(R.id.title_text_view) val container: LinearLayout itemView.findViewById(R.id.item_container) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { val view LayoutInflater.from(parent.context) .inflate(R.layout.lr_fragment_item, parent, false) return ItemViewHolder(view) } override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { val lrItem itemList[position] holder.titleTextView.text lrItem.title holder.container.setOnClickListener { listener.setOnItemClick(position, lrItem) selectedPosition position notifyDataSetChanged() } holder.container.setOnLongClickListener { listener.setOnLongClickListener(position, lrItem) true } if(selectedPosition position){ holder.container.setBackgroundColor(ContextCompat.getColor(MyApp.myApp, R.color.lr_item_selected_bg)) } else { holder.container.setBackgroundColor(ContextCompat.getColor(MyApp.myApp, R.color.lr_item_default_bg)) } } override fun getItemCount(): Int itemList.size }package com.example.androidkotlindemo2.pad.leftright import android.os.Bundle import android.widget.Button import androidx.appcompat.app.AppCompatActivity import com.example.androidkotlindemo2.R import com.example.androidkotlindemo2.utils.LogUtils /** * Author : wn * Email : maoning20080809163.com * Date : 2025/9/6 13:04 * Description : 打开新的页面 */ classLRNewActivity: AppCompatActivity(){ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.lr_activity_new) LogUtils.e(LRNewActivity onViewCreated ----------------------------) findViewByIdButton(R.id.lr_activity_new_close).setOnClickListener { finish() } } override fun onCreateDescription(): CharSequence? { return super.onCreateDescription() } override fun onDestroy() { super.onDestroy() LogUtils.e(LRNewActivity onDestroy ----------------------------) } }package com.example.androidkotlindemo2.pad.leftright /** * Author : wn * Email : maoning20080809163.com * Date : 2025/9/6 9:46 * Description : */ interfaceLROnItemClickInter{ //点击 fun setOnItemClick(position: Int, lrItem: LRItem) //长按 fun setOnLongClickListener(position: Int, lrItem: LRItem) }package com.example.androidkotlindemo2.pad.leftright import android.os.Bundle import android.widget.Button import androidx.appcompat.app.AppCompatActivity import com.example.androidkotlindemo2.R import com.example.androidkotlindemo2.utils.LogUtils /** * Author : wn * Email : maoning20080809163.com * Date : 2025/9/6 13:04 * Description : 在Activity中显示右边的fragment */ classLRRightActivity: AppCompatActivity(){ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.lr_activity_right) val lrItem intent.getParcelableExtraLRItem(lr_item) as LRItem if (savedInstanceState null) { supportFragmentManager.beginTransaction() .replace(R.id.fragment_right_container, LRDetailReplaceFragment.newInstance(lrItem)) .commit() } } }package com.example.androidkotlindemo2.pad.leftright import android.os.Parcel import android.os.Parcelable /** * Author : wn * Email : maoning20080809163.com * Date : 2025/8/30 21:41 * Description : */ data classLRItem( val id: Int, val title: String, val description: String, val imageUrl: String? null ) : Parcelable { constructor(parcel: Parcel) : this( parcel.readInt(), parcel.readString() ?: , parcel.readString() ?: , parcel.readString() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) parcel.writeString(title) parcel.writeString(description) parcel.writeString(imageUrl) } override fun describeContents(): Int { return 0 } companion object CREATOR : Parcelable.CreatorLRItem { override fun createFromParcel(parcel: Parcel): LRItem { return LRItem(parcel) } override fun newArray(size: Int): ArrayLRItem? { return arrayOfNulls(size) } } }lr_fragment_main.xml布局?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationhorizontal android:weightSum2 FrameLayout android:idid/fragment_list_container android:layout_width300dp android:layout_heightmatch_parent / TextView android:layout_width1dp android:layout_heightmatch_parent android:backgroundcolor/blue/ FrameLayout android:idid/fragment_detail_container android:layout_widthmatch_parent android:layout_heightmatch_parent/ /LinearLayoutlr_fragment_item_list.xml布局?xml version1.0 encodingutf-8? androidx.recyclerview.widget.RecyclerView xmlns:androidhttp://schemas.android.com/apk/res/android android:idid/recycler_view android:layout_widthmatch_parent android:layout_heightmatch_parent android:padding8dp /lr_fragment_item_detail.xml布局?xml version1.0 encodingutf-8? ScrollView xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:backgroundcolor/gray_e5e5e5 android:padding16dp LinearLayout android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationvertical androidx.appcompat.widget.AppCompatButton android:idid/lr_item_details_finish android:layout_widthwrap_content android:layout_heightwrap_content android:textAllCapsfalse android:textSize30sp android:textColorcolor/green android:text关闭finish/ androidx.appcompat.widget.AppCompatButton android:idid/lr_item_details_back android:layout_widthwrap_content android:layout_heightwrap_content android:textAllCapsfalse android:textSize30sp android:textColorcolor/green android:text返回/ TextView android:idid/title_text_view android:layout_widthmatch_parent android:layout_heightwrap_content android:textSize24sp android:textStylebold android:layout_marginBottom16dp / TextView android:idid/description_text_view android:layout_widthmatch_parent android:layout_heightwrap_content android:textSize16sp / TextView android:idid/description_tip android:layout_widthmatch_parent android:layout_heightwrap_content android:textColorcolor/red android:text1-3 使用 fragment 的 replace \n 4-6使用 fragment 的add() \n 其他使用打开activity android:textSize26sp / /LinearLayout /ScrollViewlr_fragment_item.xml布局?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:apphttp://schemas.android.com/apk/res-auto android:idid/item_container android:backgrounddrawable/lr_click_item_bg android:clickabletrue android:focusabletrue android:layout_widthmatch_parent android:layout_heightwrap_content android:layout_margin4dp LinearLayout android:layout_widthmatch_parent android:layout_heightwrap_content android:padding16dp android:orientationvertical TextView android:idid/title_text_view android:layout_widthmatch_parent android:layout_heightwrap_content android:textSize18sp android:textStylebold / /LinearLayout /LinearLayoutlr_activity_new.xml布局?xml version1.0 encodingutf-8? ScrollView xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:backgroundcolor/gray_e5e5e5 android:padding16dp LinearLayout android:layout_widthmatch_parent android:layout_heightwrap_content android:orientationvertical androidx.appcompat.widget.AppCompatButton android:idid/lr_activity_new_close android:layout_widthwrap_content android:layout_heightwrap_content android:textAllCapsfalse android:text关闭/ TextView android:idid/title_text_view android:layout_widthmatch_parent android:layout_heightwrap_content android:textSize24sp android:textStylebold android:text新的Activity android:layout_marginBottom16dp / TextView android:idid/description_text_view android:layout_widthmatch_parent android:layout_heightwrap_content android:textSize16sp / /LinearLayout /ScrollViewlr_activity_right.xml布局?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:backgroundcolor/gray_e5e5e5 android:orientationvertical FrameLayout android:idid/fragment_right_container android:layout_widthmatch_parent android:layout_heightmatch_parent / /LinearLayoutdrawablelr_click_item_bg.xml?xml version1.0 encodingutf-8? selector xmlns:androidhttp://schemas.android.com/apk/res/android item android:drawablecolor/lr_item_selected_bg android:state_selectedtrue/ item android:drawablecolor/lr_item_selected_bg android:state_pressedtrue/ item android:drawablecolor/lr_item_default_bg/ /selectorcolor namelr_item_default_bg#FFFFFF/color color namelr_item_selected_bg#FF00FF/coloractivity android:name.pad.leftright.LRFragmentActivityandroid:configChangesscreenSize|smallestScreenSize|screenLayout|orientation|keyboardHidden|navigation/ activity android:name.pad.leftright.LRNewActivity/ activity android:name.pad.leftright.LRRightActivity/