Android(Kotlin) - FlexibleViewPagerHeight when you want to apply wrapContent to viewPager
Normal viewpager does not have the wrapContent attribute applied. However, someTimes we need to set height of the ViewPager to match the contents. So I created a CustomViewPager class that extends ViewPager and The CustomViewPager allows you to flexibly set height of ChildViews.
To understand this post, you must have a basic understanding of ViewPager.
Video preview
1. CustomViewPager
First of all, make a CustomViewPager that extends ViewPager.
class CustomViewPager : ViewPager {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var heightMeasureSpec = heightMeasureSpec
var height = 0
for (i in 0 until childCount) {
val child = getChildAt(i)
child.measure(
widthMeasureSpec,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
val h = child.measuredHeight
if (h > height) height = h
}
if (height != 0) {
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}
2. Make 3 ViewPagerItems
The view height and backgroundColor of eash fragment was set diffrently.
1) FlexibleFragmentFirst
class FlexibleFragmentFirst : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_flexible_first, container, false)
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/brand_purple"
tools:context=".viewPager.flexibleHeight.FlexibleFragmentFirst">
<View
android:layout_width="match_parent"
android:layout_height="300dp"/>
</FrameLayout>
2) FlexibleFragmentSecond
class FlexibleFragmentSecond : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_flexible_second, container, false)
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/brand_green"
tools:context=".viewPager.flexibleHeight.FlexibleFragmentSecond">
<View
android:layout_width="match_parent"
android:layout_height="200dp"/>
</FrameLayout>
3) FlexibleFragmentThird
class FlexibleFragmentThird : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_flexible_third, container, false)
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/brand_blue"
tools:context=".viewPager.flexibleHeight.FlexibleFragmentThird">
<View
android:layout_width="match_parent"
android:layout_height="100dp" />
</FrameLayout>
3. Make a ViewPagerAdapter
class ViewPagerAdapter : FragmentPagerAdapter {
constructor(fm: FragmentManager) : super(fm)
private var fragmentArrayList = ArrayList<Fragment>()
override fun getCount(): Int {
return fragmentArrayList.size
}
override fun getItem(position: Int): Fragment {
return fragmentArrayList[position]
}
fun addItem(fragment: Fragment) {
this.fragmentArrayList.add(fragment)
}
}
4. Now, connect the fragments inside the viewpager.
1) activity_flexible_view_pager_height.xml
To distinguish it from the viewpager, I made the backgroundColor gray.
The package path name of CustomViewPager will be different depending on your package Name.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/brand_gray"
android:orientation="vertical"
tools:context=".viewPager.flexibleHeight.FlexibleViewPagerHeightActivity">
<com.jinhanexample.viewPager.flexibleHeight.CustomViewPager
android:id="@+id/flexibleViewPager"
android:layout_width="match_parent"
android:layout_height="400dp" />
</LinearLayout>
2) FlexibleViewPagerHeightActivity
If you specify a int value for offscreenPageLimit, the height of the viewpager is set to the fragment with the largest height value. Because I set 300dp on FlexibleFragmentFirst, the height of my ViewPager is set to 300dp.
class FlexibleViewPagerHeightActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_flexible_view_pager_height)
val first = FlexibleFragmentFirst()
val second = FlexibleFragmentSecond()
val third = FlexibleFragmentThird()
flexibleViewPager.offscreenPageLimit = 3
val viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
viewPagerAdapter.addItem(first)
viewPagerAdapter.addItem(second)
viewPagerAdapter.addItem(third)
flexibleViewPager.adapter = viewPagerAdapter
}
}