How to create a dynamic height wrapping ViewPager when content have variable heights on Android.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context | |
import android.util.AttributeSet | |
import androidx.viewpager.widget.ViewPager | |
class DynamicHeightViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : ViewPager(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, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)) | |
val h = child.measuredHeight | |
if (h > height) height = h | |
} | |
if (height != 0) { | |
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) | |
} | |
super.onMeasure(widthMeasureSpec, heightMeasureSpec) | |
}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private fun renderRegionalOfferList(offers: List<Offer>?) { | |
val offerAdapter = RegionalOffersAdapter(requireContext(), localViewModel.offerClickSubject, offers) | |
binding.viewRegionalOffers.viewPager.adapter = offerAdapter | |
binding.viewRegionalOffers.viewPager.offscreenPageLimit = 2 | |
binding.viewRegionalOffers.viewPager.pageMargin=18 | |
dotscount = offerAdapter.count | |
dots = arrayOfNulls(dotscount) | |
//adding dots base don dotscount ie. total number of images | |
for (i in 0 until dotscount) { | |
dots[i] = ImageView(requireContext()) | |
dots[i]!!.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.non_active_dot)) | |
val param = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT) | |
param.setMargins(8, 0, 8, 0) | |
binding.viewRegionalOffers.sliderDots.addView(dots[i], param) | |
} | |
//0 position active by default | |
dots[0]!!.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.active_dot)) | |
//image slider listener | |
binding.viewRegionalOffers.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { | |
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { | |
} | |
override fun onPageSelected(position: Int) { | |
for (i in 0 until dotscount) { | |
dots[i]!!.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.non_active_dot)) | |
} | |
dots[position]!!.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.active_dot)) | |
} | |
override fun onPageScrollStateChanged(state: Int) { | |
} | |
}) | |
//offerAdapter.swapData(offers) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class RegionalOffersAdapter( | |
private val context: Context, | |
private val clickSubject: PublishSubject<Offer>, | |
val items: List<Offer>? | |
) : PagerAdapter() { | |
//private val items = mutableListOf<Offer>() | |
override fun getCount(): Int = items?.size ?: 0 | |
override fun instantiateItem(container: ViewGroup, position: Int): Any { | |
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater | |
val view = inflater.inflate(R.layout.item_regional_offer, null) | |
val image = view.findViewById<ImageView>(R.id.image) | |
val offerTitle = view.findViewById<TextView>(R.id.offer_title) | |
val name = view.findViewById<TextView>(R.id.name) | |
val ratingFollowers = view.findViewById<TextView>(R.id.rating_followers) | |
val amount = view.findViewById<TextView>(R.id.amount) | |
val categoryLocationContainer = view.findViewById<FancyCategoryLocationChipView>(R.id.category_location_container) | |
name.text = items?.get(position)?.createdByCompany?.user?.name ?: "Company" | |
offerTitle.text = items?.get(position)?.name ?: "Test offer" | |
image.setImageBitmap( | |
BitmapFactory.decodeResource( | |
view.context.resources, | |
R.drawable.profile_placeholder | |
) | |
) | |
amount.text = "${items?.get(position)?.rewards?.get(0)?.unit ?: "$"} ${items?.get(position)?.rewards?.get(0)?.amount ?: "0"}" | |
view.setOnClickListener { | |
InfluencerOfferDetailsActivity.start(context, items?.get(position)?.id ?: 0) | |
} | |
items?.get(position)?.mainImage?.let { | |
Picasso.get().load(it.getImagePath()) | |
.placeholder(R.drawable.profile_placeholder) | |
.error(R.drawable.profile_placeholder) | |
.into(image) | |
} | |
//offerContainer.setOnClickListener { clickSubject.onNext(offerModel) } | |
ratingFollowers.text = "Rating: ${items?.get(position)?.createdByCompany?.user?.calculatedRating ?: 0} | ${items?.get(position)?.minimumAudienceCount} Min Followers" | |
categoryLocationContainer.setupView3(context, items?.get(position)?.categories, items?.get(position)?.audienceLocations) | |
//categoryLocationContainer.setupView(context) | |
val vp = container as ViewPager | |
vp.addView(view, 0) | |
return view | |
} | |
override fun isViewFromObject(view: View, `object`: Any): Boolean { | |
return view === `object` | |
} | |
fun swapData(items: List<Offer>?) { | |
/* this.items.clear() | |
if (!items.isNullOrEmpty()) { | |
this.items.addAll(items.sortedWith(compareBy { it.status?.shortName })) | |
} | |
notifyDataSetChanged()*/ | |
} | |
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { | |
val vp = container as ViewPager | |
val view = `object` as View | |
vp.removeView(view) | |
} | |
override fun getPageWidth(position: Int): Float { | |
return .8f | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<layout xmlns:tools="http://schemas.android.com/tools" | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto"> | |
<androidx.constraintlayout.widget.ConstraintLayout | |
android:layout_width="match_parent" | |
android:id="@+id/regionalOfferContainer" | |
android:backgroundTint="@color/white" | |
android:background="@drawable/top_rounded_background" | |
android:layout_height="wrap_content"> | |
<TextView | |
android:id="@+id/textView9" | |
android:layout_width="0dp" | |
android:layout_height="wrap_content" | |
android:layout_marginStart="24dp" | |
android:layout_marginTop="22dp" | |
android:layout_marginEnd="16dp" | |
android:fontFamily="@font/montserrat_semi_bold" | |
android:text="@string/label_regional_offers" | |
android:textColor="@color/fancy_black_60" | |
android:textSize="15sp" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintTop_toTopOf="parent" /> | |
<com.sway.android.utils.view.DynamicHeightViewPager | |
android:id="@+id/viewPager" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_marginStart="30dp" | |
android:layout_marginBottom="8dp" | |
android:layout_marginTop="18dp" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintTop_toBottomOf="@+id/textView9"> | |
</com.sway.android.utils.view.DynamicHeightViewPager> | |
<LinearLayout | |
android:id="@+id/sliderDots" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_marginBottom="16dp" | |
android:layout_marginTop="8dp" | |
android:orientation="horizontal" | |
app:layout_constraintBottom_toBottomOf="parent" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintTop_toBottomOf="@+id/viewPager" /> | |
</androidx.constraintlayout.widget.ConstraintLayout> | |
</layout> |
No comments :
Post a Comment