#android #android-fragments #android-viewpager
#Android #android-фрагменты #android-viewpager
Вопрос:
На картинке ниже вы можете увидеть желаемый макет:
Итак, ViewPager состоит из трех страниц, левая и правая страницы статически заполнены двумя фрагментами (фрагмент 1 и фрагмент 2), а страница в центре должна иметь макет, в котором панель инструментов сверху, нижняя панель инструментов снизу и фрагмент между ними, который можно динамически изменять.
Насколько я вижу, это можно сделать двумя способами.
-
Сотворите волшебство с центральной страницей, на которой будут обе панели инструментов и динамически устанавливаться Fragment0
-
Каждый фрагмент, который должен переходить на страницу в центре, должен иметь эти панели инструментов и одинаковый способ обработки событий от них, т. е. подкласс на
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
}
}