Как установить ViewPager с двумя фрагментами сбоку, со средней страницей, заполненной представлениями, и другим фрагментом?

#android #android-fragments #android-viewpager

#Android #android-фрагменты #android-viewpager

Вопрос:

На картинке ниже вы можете увидеть желаемый макет:

введите описание изображения здесь

Итак, ViewPager состоит из трех страниц, левая и правая страницы статически заполнены двумя фрагментами (фрагмент 1 и фрагмент 2), а страница в центре должна иметь макет, в котором панель инструментов сверху, нижняя панель инструментов снизу и фрагмент между ними, который можно динамически изменять.

Насколько я вижу, это можно сделать двумя способами.

  1. Сотворите волшебство с центральной страницей, на которой будут обе панели инструментов и динамически устанавливаться Fragment0

  2. Каждый фрагмент, который должен переходить на страницу в центре, должен иметь эти панели инструментов и одинаковый способ обработки событий от них, т. е. подкласс на AbstractCenterFragment , который содержит все необходимое для реализации этого макета и поведения.

Даже если было бы проще реализовать решение 2, мне это совсем не нравится по многим причинам. Я не буду рассматривать их здесь, но если вы настаиваете, я могу их предоставить.

Что касается решения 1, есть ли что-нибудь, что вы можете предложить для решения этой проблемы на уровне активности, поскольку activity со всеми его компонентами (viewmodel и т.д.) Должен Обрабатывать этот макет?

Если я использую FragmentPagerAdapter for ViewPager и создам родительский фрагмент на центральной странице, который содержит панель инструментов, нижнюю панель инструментов и Fragment0, как это повлияет на производительность?

Есть ли у вас какие-либо другие предложения по использованию какого-либо другого типа PagerAdapter , которого будет достаточно для обработки поведения данного макета?

Спасибо!

PS если вы дадите -1 на этот вопрос, пожалуйста, будьте достаточно вежливы, чтобы объяснить, почему вы его задали.

Ответ №1:

Хорошо, я создал гибридное решение между FragmentViewPagerAdapter и обычной реализацией ViewPagerAdapter с заданным макетом.

Вот оно:

 
abstract class NoMiddleFragmentPagerAdapter(private val mFragmentManager: FragmentManager) : PagerAdapter() {
    private var mCurTransaction: FragmentTransaction? = null
    private var mCurrentPrimaryItem: Fragment? = null

    abstract fun getLeftItem(): Fragment

    abstract fun getRightItem(): Fragment

    @Throws(IllegalStateException::class)
    override fun startUpdate(container: ViewGroup) {
        if (container.id == View.NO_ID) {
            throw IllegalStateException( "ViewPager with adapter $this requires a view id.")
        }
    }

    override fun instantiateItem(container: ViewGroup, position: Int): Any = if (position == MIDDLE) instantiateCentralArea(container, position) else instantiateFragment(container, position)

    private fun instantiateFragment(container: ViewGroup, position: Int) : Fragment {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction()
        }

        val itemId = getItemId(position)

        // Do we already have this fragment?
        val name = makeFragmentName(container.id, itemId)
        var fragment = mFragmentManager.findFragmentByTag(name)
        if (fragment != null) {
            mCurTransaction!!.attach(fragment)
        } else {
            fragment = if (position == LEFT) getLeftItem() else getRightItem()
            mCurTransaction!!.add(
                container.id, fragment,
                makeFragmentName(container.id, itemId)
            )
        }
        if (fragment !== mCurrentPrimaryItem) {
            fragment.setMenuVisibility(false)
            fragment.userVisibleHint = false
        }

        return fragment
    }

    abstract fun instantiateCentralArea(container: ViewGroup, position: Int): Any

    override fun getCount(): Int = 3

    override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) = if (position == MIDDLE) destroyMiddlePart(container, `object`) else destroyFragment(container, position, `object`)

    private fun destroyFragment(container: ViewGroup, position: Int, any: Any) {
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction()
        }
        mCurTransaction!!.detach(any as Fragment)
    }

    private fun destroyMiddlePart(container: ViewGroup, `object`: Any) = container.removeView(`object` as View)

    override fun setPrimaryItem(container: ViewGroup, position: Int, o: Any) {
        if (o !is Fragment) {
            super.setPrimaryItem(container, position, o)
            return
        }
        if (o !== mCurrentPrimaryItem) {
            if (mCurrentPrimaryItem != null) {
                mCurrentPrimaryItem!!.setMenuVisibility(false)
                mCurrentPrimaryItem!!.userVisibleHint = false
            }
            o.setMenuVisibility(true)
            o.userVisibleHint = true
            mCurrentPrimaryItem = o
        }
    }

    override fun finishUpdate(container: ViewGroup) {
        if (mCurTransaction != null) {
            mCurTransaction!!.commitNowAllowingStateLoss()
            mCurTransaction = null
        }
    }

    override fun isViewFromObject(view: View, any: Any): Boolean {
        return when (any) {
            is Fragment -> any.view == view
            is View -> view === any
            else -> false
        }
    }

    override fun saveState(): Parcelable? {
        return null
    }

    override fun restoreState(state: Parcelable?, loader: ClassLoader?) {}

    fun getItemId(position: Int): Long {
        return position.toLong()
    }

    companion object {
        private const val LEFT = 0
        private const val MIDDLE = 1
        private const val RIGHT = 2

        private fun makeFragmentName(viewId: Int, id: Long): String {
            return "android:switcher:$viewId:$id"
        }
    }
}
  

При реализации этого адаптера в Activity я создал следующий класс:

 private class HomePageAdapter(private val layoutInflater: LayoutInflater, fragmentManager: FragmentManager) : NoMiddleFragmentPagerAdapter(fragmentManager) {

        override fun getLeftItem(): Fragment = LeftFragment()

        override fun getRightItem(): Fragment = RightFragment()

        override fun instantiateCentralArea(container: ViewGroup, position: Int): Any {
            val view = layoutInflater.inflate(R.layout.main_content_area, container, false)
            container.addView(view)
            return view
        }
    }