【问题标题】:How can I start a Fragment from within another Fragment that's part of a viewPager?如何从属于 viewPager 的另一个 Fragment 中启动一个 Fragment?
【发布时间】:2020-03-03 05:33:48
【问题描述】:

我刚刚开始使用 Kotlin 进行 Android 开发,我不太确定解决这种情况的正确方法是什么。

基本上我想要做的是有一个ViewPager 滚动浏览相同类型的项目列表。与每个项目关联的视图都有一个按钮。当我按下按钮时,我想启动一个新片段,我们称之为iteminfo。 iteminfo 片段应该使用后退堆栈,以便您可以点击后退按钮并返回到您在点击按钮之前查看的项目视图。

我现在的设置方式是这样的:

-My MainActivity 将包含 ViewPager 的片段添加()到 FragmentManager。 (我打算采用单一活动架构。)

-我的 ViewPager 片段包含一个带有PagerAdapter 的私有内部类,该类维护一个项目片段列表。在创建 ViewPager 片段时会生成项目片段并将其添加到 PagerAdapter。

-每个项目片段都有自己的按钮。创建片段时,按钮会获得一个onClickListener。

这是我遇到了一些死胡同的地方......

到目前为止,我已经设法让 iteminfo 片段显示并让 item 片段消失,但我的方法非常笨拙:我执行了一个片段事务,将 iteminfo 片段添加()到我的 item_fragment 的根元素。 xml,然后将其中其他元素的可见性设置为 GONE。从外观上看,这让我到了那里,但是如果我点击后退按钮,应用程序就会退出。所以这不会削减它。

我已经读过,在片段视图之间切换时,使用 .xml 文件中的单个空 FrameLayout 作为片段容器,然后使用 FragmentManager 添加/删除片段是一个很好的设计。这对我来说很有意义......

但是,我不确定如何删除()ViewPager 内的片段。 AFAIK 除非您正在进行片段交易,否则您无法设置片段的标签。所以如果我想执行replace(),我不知道如何引用我要替换的片段。

就像 Hail-Mary 一样,我尝试只替换整个 ViewPager 片段(因为这是通过片段事务添加到 MainActivity 中的,所以我能够对其进行标记),但由于某种原因,这只会产生 NPE。子片段不能替换其父片段是有道理的,尽管我不能 100% 确定它为什么是 NPE。

无论如何,非常感谢您能给我带来的任何启发。

编辑:在下面添加了相关代码。

MainActivity.kt:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val currentFragment = supportFragmentManager
            .findFragmentById(R.id.fragment_container)

        if (currentFragment == null) {
            val fragment = ItemPagerFragment.newInstance()
            supportFragmentManager
                .beginTransaction()
                .add(R.id.fragment_container, fragment, "viewPager")
                .commit()
        }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</FrameLayout>

ItemPagerFragment.kt:

class ItemPagerFragment: Fragment() {

    private lateinit var viewPager: ViewPager
    private lateinit var pagerAdapter: ItemPagerAdapter

    private val itemListViewModel:  ItemListViewModel by lazy {
        ViewModelProviders.of(this).get(ItemListViewModel::class.java)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val view = inflater.inflate(R.layout.fragment_item_pager, container, false)

        viewPager = view.findViewById(R.id.item_viewpager) as ViewPager
        pagerAdapter = ItemPagerAdapter(getChildFragmentManager())

        val items = itemListViewModel.items
        for (item in items){
            pagerAdapter.addFrag(ItemFragment.newInstance(item))
        }

        viewPager.adapter = pagerAdapter

        return view
    }

    private inner class ItemPagerAdapter(fm: FragmentManager)
        : FragmentStatePagerAdapter(fm)
    {

        private val itemFragmentList: MutableList<ItemFragment> = ArrayList()

        override fun getItem(i: Int): Fragment {
            return itemFragmentList[i]
        }

        override fun getCount() = itemFragmentList.size

        fun addFrag(f: ItemFragment){
            itemFragmentList.add(f)
        }

    }

    companion object {
        fun newInstance(): ItemPagerFragment {
            return ItemPagerFragment()
        }
    }

}

fragment_item_pager.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager.widget.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

ItemFragment.kt:

class ItemFragment(i: Item): Fragment() {

    private var item: Item = i;
    private lateinit var infoButton: Button

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_item, container, false)

        infoButton = view.findViewById(R.id.info_button) as Button

        infoButton.setOnClickListener{
            val fragment: InfoFragment =  InfoFragment.newInstance(item)
            val fragmentManager: FragmentManager = childFragmentManager
            val fragmentTransaction = fragmentManager.beginTransaction()

            // this is where I have been having no success
            // and know my approach is certainly wrong/confused
            fragmentTransaction.replace(R.id.item_frame, fragment)
            fragmentTransaction.addToBackStack(null)
            fragmentTransaction.commit()
        }

        return view
    }

    companion object {
        fun newInstance(i: Item): ItemFragment {
            return ItemFragment(i)
        }
    }

}

fragment_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_frame"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp">

    <Button
        android:id="@+id/info_button"
        android:layout_gravity="center|bottom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/some_string"
        />

</FrameLayout>

InfoFragment.kt 和 fragment_info.xml 可以是任何东西,就我的问题而言,它们是什么并不重要。

【问题讨论】:

  • 包含您所做的代码,然后任何人都可以提供解决方案。

标签: android android-fragments kotlin android-viewpager


【解决方案1】:

如果我正确理解您的问题,这里的解决方案非常简单。

您有一个 Activity,其中有一个 FrameLayout,它是一个片段容器。实际上,您将片段与 ViewPager 放在其中。当您单击按钮时,您只需使用 ViewPager 将新片段放在片段顶部。

底线是所有动作都必须通过 Activity 发生。那些。您必须有一个您的 Activity 将实现的接口,并且片段将从上下文中接收其实例(例如,在片段的 onAttach () 方法中)。当您单击按钮时,您只需将事件传递给 Activity。并且 Activity 已经在创建一个新的 Fragment,从而保留了 backstack。

重要的是要了解,在处理片段时,它们不应该知道彼此的存在。所有操作都必须通过抽象发生并由您的 parentView(Activity、ParentFragmen 等)执行

【讨论】:

    猜你喜欢
    • 2013-09-06
    • 1970-01-01
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多