From 49984cb6518dc860153751f95a4321878af9a86a Mon Sep 17 00:00:00 2001 From: klaus Date: Thu, 28 May 2026 11:14:02 +0900 Subject: [PATCH] =?UTF-8?q?feat(banner):=20=EB=B0=B0=EB=84=88=20wrap=20con?= =?UTF-8?q?tent=20=EB=86=92=EC=9D=B4=EB=A5=BC=20=EC=A7=80=EC=9B=90?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../sodalive/v2/widget/banner/BannerView.kt | 15 +++++++++ .../v2/widget/banner/BannerViewTest.kt | 32 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerView.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerView.kt index d32f82b2..281e7c78 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerView.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerView.kt @@ -74,6 +74,21 @@ class BannerView @JvmOverloads constructor( super.onDetachedFromWindow() } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val widthSize = MeasureSpec.getSize(widthMeasureSpec) + val heightMode = MeasureSpec.getMode(heightMeasureSpec) + val measuredHeightSpec = if (widthSize > 0 && heightMode != MeasureSpec.EXACTLY) { + val density = resources.displayMetrics.density + val screenWidthDp = (widthSize / density).roundToInt() + val desiredHeight = BannerLayoutCalculator.calculate(screenWidthDp, density).itemHeightDp.dpToPx() + MeasureSpec.makeMeasureSpec(desiredHeight, MeasureSpec.EXACTLY) + } else { + heightMeasureSpec + } + super.onMeasure(widthMeasureSpec, measuredHeightSpec) + } + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) if (w > 0) applyLayoutSize(w) diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerViewTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerViewTest.kt index bb078d84..00f90866 100644 --- a/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerViewTest.kt +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/widget/banner/BannerViewTest.kt @@ -120,6 +120,36 @@ class BannerViewTest { assertEquals(362.dpToPx(), holder.itemView.layoutParams.height) } + @Test + fun `배너 view는 wrap content 높이면 402dp 폭 기준 362dp 높이로 측정된다`() { + val view = inflateBannerView() + + view.setItems(listOf(sampleItem("1"), sampleItem("2"))) + view.measure(exactly(402.dpToPx()), atMost(1_000.dpToPx())) + + assertEquals(362.dpToPx(), view.measuredHeight) + } + + @Test + fun `배너 view는 wrap content 높이면 360dp 폭 기준 320dp 높이로 측정된다`() { + val view = inflateBannerView() + + view.setItems(listOf(sampleItem("1"), sampleItem("2"))) + view.measure(exactly(360.dpToPx()), atMost(1_000.dpToPx())) + + assertEquals(320.dpToPx(), view.measuredHeight) + } + + @Test + fun `배너 view는 명시 높이면 부모 측정 높이를 유지한다`() { + val view = inflateBannerView() + + view.setItems(listOf(sampleItem("1"), sampleItem("2"))) + view.measure(exactly(402.dpToPx()), exactly(500.dpToPx())) + + assertEquals(500.dpToPx(), view.measuredHeight) + } + @Test fun `배너 view는 단일 item이면 item 간격을 적용하지 않는다`() { val view = inflateBannerView() @@ -303,6 +333,8 @@ class BannerViewTest { private fun exactly(size: Int): Int = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY) + private fun atMost(size: Int): Int = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST) + private fun Int.dpToPx(): Int { val context = ApplicationProvider.getApplicationContext() return (this * context.resources.displayMetrics.density).toInt()