Как установить ViewPager с двумя фрагментами на стороне со средней страницей, заполненной представлениями, и другим фрагментом? - PullRequest
0 голосов
/ 29 марта 2019

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

enter image description here

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

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

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

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

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

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

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

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

Спасибо!

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

1 Ответ

0 голосов
/ 01 апреля 2019

Хорошо, я сделал гибридное решение между 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
        }
    }
...