From feb296a883368c7b422c4d15bcef5d2e08ab41e6 Mon Sep 17 00:00:00 2001 From: skydoves Date: Sun, 5 Apr 2020 07:25:41 +0900 Subject: [PATCH 1/3] Fix setMeasureHeight functionality --- app/src/main/AndroidManifest.xml | 2 +- .../expandablelayoutdemo/MainActivity.kt | 2 +- app/src/main/res/layout/item_row.xml | 3 +- app/src/main/res/layout/layout_parent.xml | 12 ++--- app/src/main/res/layout/layout_second1.xml | 8 ++-- app/src/main/res/layout/layout_second2.xml | 11 ++--- app/src/main/res/values/strings.xml | 4 +- .../expandablelayout/ExpandableLayout.kt | 44 ++++--------------- .../res/layout/expandable_layout_parent.xml | 2 +- 9 files changed, 35 insertions(+), 53 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ff6e6ca..6da7834 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,7 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" - tools:ignore="GoogleAppIndexingWarning"> + tools:ignore="AllowBackup,GoogleAppIndexingWarning"> diff --git a/app/src/main/java/com/skydoves/expandablelayoutdemo/MainActivity.kt b/app/src/main/java/com/skydoves/expandablelayoutdemo/MainActivity.kt index 0843b87..1e9dcd8 100644 --- a/app/src/main/java/com/skydoves/expandablelayoutdemo/MainActivity.kt +++ b/app/src/main/java/com/skydoves/expandablelayoutdemo/MainActivity.kt @@ -58,7 +58,7 @@ class MainActivity : AppCompatActivity() { if (expandable1.isExpanded) { expandable1.collapse() } else { - expandable1.expand(370) + expandable1.expand() } } expandable1.secondLayout.setOnClickListener { toast("clicked the second layout") } diff --git a/app/src/main/res/layout/item_row.xml b/app/src/main/res/layout/item_row.xml index 95bbb94..bd5d553 100644 --- a/app/src/main/res/layout/item_row.xml +++ b/app/src/main/res/layout/item_row.xml @@ -5,7 +5,8 @@ android:layout_height="wrap_content" android:background="@color/background800" android:foreground="?attr/selectableItemBackground" - android:orientation="vertical"> + android:orientation="vertical" + tools:ignore="UnusedAttribute"> - + android:gravity="center" + android:padding="16dp" + tools:ignore="UnusedAttribute"> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_second1.xml b/app/src/main/res/layout/layout_second1.xml index d5ecf58..d8d6bba 100644 --- a/app/src/main/res/layout/layout_second1.xml +++ b/app/src/main/res/layout/layout_second1.xml @@ -1,16 +1,18 @@ + android:padding="10dp" + tools:ignore="UnusedAttribute"> diff --git a/app/src/main/res/layout/layout_second2.xml b/app/src/main/res/layout/layout_second2.xml index 3abe9f0..312ed87 100644 --- a/app/src/main/res/layout/layout_second2.xml +++ b/app/src/main/res/layout/layout_second2.xml @@ -1,8 +1,9 @@ - - + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ce1826d..8a3ccff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ - ExpandableLayoutDemo + ExpandableLayoutDemo + Travelocity has some of the best prices on vacation packages guaranteed. Book your flight and hotel together to save money today! + All men have stars, but they are not the same things for different people. For some, who are travelers, the stars are guides. For others they are no more than little lights in the sky. For others, who are scholars, they are problems... But all these stars are silent. You-You alone will have stars as no one else has them. diff --git a/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt b/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt index 5272762..797d965 100644 --- a/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt +++ b/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt @@ -24,7 +24,6 @@ import android.graphics.Color import android.graphics.drawable.Drawable import android.util.AttributeSet import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import android.widget.RelativeLayout @@ -32,12 +31,10 @@ import androidx.annotation.ColorInt import androidx.annotation.LayoutRes import androidx.annotation.Px import androidx.core.widget.ImageViewCompat -import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.expandable_layout_parent.view.arrow import kotlinx.android.synthetic.main.expandable_layout_parent.view.cover /** An expandable layout that shows a two-level layout with an indicator. */ -@Suppress("unused") class ExpandableLayout : FrameLayout { lateinit var parentLayout: ViewGroup @@ -181,12 +178,14 @@ class ExpandableLayout : FrameLayout { private fun updateSecondLayout() { this.secondLayout = inflate(this.secondLayoutResource) - with(this.secondLayout) { + with(secondLayout) { updateLayoutParams { height = 0 } y = parentLayout.measuredHeight.toFloat() } - addView(this.secondLayout) - setMeasureHeight(secondLayout) + addView(secondLayout) + secondLayout.post { + secondLayoutHeight = setMeasureHeight(secondLayout) + } } private fun updateSpinner() { @@ -211,42 +210,16 @@ class ExpandableLayout : FrameLayout { private fun setMeasureHeight(parent: ViewGroup): Int { parent.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) - var height = parent.height - height += getTopBottomPaddingSize(parent) - height += getTopBottomMarginSize(parent) + var height = parent.measuredHeight for (i in 0 until parent.childCount) { val child = parent.getChildAt(i) - child.post { - child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) - height += when (child) { - is ExpandableLayout -> child.height + child.secondLayoutHeight - is RecyclerView -> child.measuredHeight - is ViewGroup -> setMeasureHeight(child) - else -> child.measuredHeight - } - height += getTopBottomPaddingSize(child) - height += getTopBottomMarginSize(child) - if (height > this.secondLayoutHeight) { - this.secondLayoutHeight = height - } + if (child is ExpandableLayout) { + height += setMeasureHeight(child) } } return height } - private fun getTopBottomPaddingSize(view: View): Int { - return view.paddingTop + view.paddingBottom - } - - private fun getTopBottomMarginSize(view: View): Int { - var margin = 0 - if (view.layoutParams is MarginLayoutParams) { - val marginLayoutParams = (view.layoutParams as MarginLayoutParams) - margin += marginLayoutParams.topMargin + marginLayoutParams.bottomMargin - } - return margin - } - /** * This function is for supporting Java language. * Expand the second layout with indicator animation. @@ -327,6 +300,7 @@ class ExpandableLayout : FrameLayout { } /** Builder class for creating [ExpandableLayout]. */ + @Suppress("unused") @ExpandableLayoutDsl class Builder(context: Context) { private val expandableLayout = ExpandableLayout(context) diff --git a/expandablelayout/src/main/res/layout/expandable_layout_parent.xml b/expandablelayout/src/main/res/layout/expandable_layout_parent.xml index c83218f..80ffb29 100644 --- a/expandablelayout/src/main/res/layout/expandable_layout_parent.xml +++ b/expandablelayout/src/main/res/layout/expandable_layout_parent.xml @@ -8,7 +8,7 @@ + android:layout_height="wrap_content" /> Date: Sun, 5 Apr 2020 07:49:38 +0900 Subject: [PATCH 2/3] Refactor getMeasuredHeight functionality --- app/build.gradle | 4 +--- .../expandablelayoutdemo/MainActivity.kt | 9 +++++++-- app/src/main/res/layout/activity_main.xml | 1 + app/src/main/res/layout/layout_second2.xml | 2 +- dependencies.gradle | 7 +++---- expandablelayout/build.gradle | 1 - .../expandablelayout/ExpandableLayout.kt | 17 +++++++++-------- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 98950c7..ae64ee5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,10 +16,8 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin" - implementation "androidx.appcompat:appcompat:$versions.androidxAppcompat" - implementation "androidx.cardview:cardview:$versions.cardView" + implementation "com.google.android.material:material:$versions.googleMaterial" implementation "com.github.skydoves:baserecyclerviewadapter:$versions.baseAdapter" - implementation "androidx.recyclerview:recyclerview:$versions.recyclerView" implementation project(":expandablelayout") } diff --git a/app/src/main/java/com/skydoves/expandablelayoutdemo/MainActivity.kt b/app/src/main/java/com/skydoves/expandablelayoutdemo/MainActivity.kt index 1e9dcd8..50181fa 100644 --- a/app/src/main/java/com/skydoves/expandablelayoutdemo/MainActivity.kt +++ b/app/src/main/java/com/skydoves/expandablelayoutdemo/MainActivity.kt @@ -19,8 +19,13 @@ package com.skydoves.expandablelayoutdemo import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import kotlinx.android.synthetic.main.activity_main.* -import kotlinx.android.synthetic.main.layout_second.view.* +import kotlinx.android.synthetic.main.activity_main.expandable +import kotlinx.android.synthetic.main.activity_main.expandable1 +import kotlinx.android.synthetic.main.activity_main.expandable2 +import kotlinx.android.synthetic.main.layout_second.view.button0 +import kotlinx.android.synthetic.main.layout_second.view.button1 +import kotlinx.android.synthetic.main.layout_second.view.button2 +import kotlinx.android.synthetic.main.layout_second.view.button3 class MainActivity : AppCompatActivity() { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ef0d96b..35d987e 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,6 +1,7 @@ diff --git a/dependencies.gradle b/dependencies.gradle index fe2223f..7416cf1 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -5,15 +5,14 @@ ext.versions = [ versionName : '1.0.4', gradleBuildTool : '3.5.3', - spotlessGradle : '3.26.1', + spotlessGradle : '3.28.0', dokkaGradle : '0.9.17', bintrayRelease : '0.9.1', - kotlin : '1.3.61', + kotlin : '1.3.70', androidxAppcompat : '1.1.0', // for demo - cardView : '1.0.0', - recyclerView : '1.1.0', + googleMaterial : '1.2.0-alpha05', baseAdapter : '0.1.3' ] diff --git a/expandablelayout/build.gradle b/expandablelayout/build.gradle index 17f7481..6534135 100644 --- a/expandablelayout/build.gradle +++ b/expandablelayout/build.gradle @@ -19,7 +19,6 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin" implementation "androidx.appcompat:appcompat:$versions.androidxAppcompat" - implementation "androidx.recyclerview:recyclerview:$versions.recyclerView" } dokka { diff --git a/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt b/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt index 797d965..d8e8ac0 100644 --- a/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt +++ b/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt @@ -177,14 +177,14 @@ class ExpandableLayout : FrameLayout { } private fun updateSecondLayout() { - this.secondLayout = inflate(this.secondLayoutResource) - with(secondLayout) { - updateLayoutParams { height = 0 } - y = parentLayout.measuredHeight.toFloat() - } + secondLayout = inflate(secondLayoutResource) addView(secondLayout) secondLayout.post { secondLayoutHeight = setMeasureHeight(secondLayout) + with(secondLayout) { + updateLayoutParams { height = 0 } + y = parentLayout.measuredHeight.toFloat() + } } } @@ -209,12 +209,13 @@ class ExpandableLayout : FrameLayout { } private fun setMeasureHeight(parent: ViewGroup): Int { - parent.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) - var height = parent.measuredHeight + var height = parent.height for (i in 0 until parent.childCount) { val child = parent.getChildAt(i) if (child is ExpandableLayout) { - height += setMeasureHeight(child) + child.post { + height += setMeasureHeight(child) + } } } return height From b36b3f433d136dfac12efcc3b3b56aadd4d3147a Mon Sep 17 00:00:00 2001 From: skydoves Date: Sun, 5 Apr 2020 07:59:32 +0900 Subject: [PATCH 3/3] Change parentLayout and secondLayout to View --- .../expandablelayout/ExpandableLayout.kt | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt b/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt index d8e8ac0..06cbbad 100644 --- a/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt +++ b/expandablelayout/src/main/java/com/skydoves/expandablelayout/ExpandableLayout.kt @@ -24,6 +24,7 @@ import android.graphics.Color import android.graphics.drawable.Drawable import android.util.AttributeSet import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import android.widget.RelativeLayout @@ -37,8 +38,8 @@ import kotlinx.android.synthetic.main.expandable_layout_parent.view.cover /** An expandable layout that shows a two-level layout with an indicator. */ class ExpandableLayout : FrameLayout { - lateinit var parentLayout: ViewGroup - lateinit var secondLayout: ViewGroup + lateinit var parentLayout: View + lateinit var secondLayout: View private lateinit var parentFrameLayout: RelativeLayout @LayoutRes var parentLayoutResource: Int = R.layout.expandable_layout_parent set(value) { @@ -125,7 +126,7 @@ class ExpandableLayout : FrameLayout { a.getResourceId(R.styleable.ExpandableLayout_expandable_secondLayout, this.secondLayoutResource) this.duration = - a.getInteger(R.styleable.ExpandableLayout_expandable_duration, this.duration.toInt()).toLong() + a.getInteger(R.styleable.ExpandableLayout_expandable_duration, duration.toInt()).toLong() val animation = a.getInteger(R.styleable.ExpandableLayout_expandable_animation, this.expandableAnimation.value) @@ -136,19 +137,19 @@ class ExpandableLayout : FrameLayout { } this.spinnerDrawable = a.getDrawable(R.styleable.ExpandableLayout_expandable_spinner) this.showSpinner = - a.getBoolean(R.styleable.ExpandableLayout_expandable_showSpinner, this.showSpinner) + a.getBoolean(R.styleable.ExpandableLayout_expandable_showSpinner, showSpinner) this.spinnerAnimate = - a.getBoolean(R.styleable.ExpandableLayout_expandable_spinner_animate, this.spinnerAnimate) + a.getBoolean(R.styleable.ExpandableLayout_expandable_spinner_animate, spinnerAnimate) this.spinnerRotation = - a.getInt(R.styleable.ExpandableLayout_expandable_spinner_rotation, this.spinnerRotation) + a.getInt(R.styleable.ExpandableLayout_expandable_spinner_rotation, spinnerRotation) this.spinnerSize = - a.getDimension(R.styleable.ExpandableLayout_expandable_spinner_size, this.spinnerSize) + a.getDimension(R.styleable.ExpandableLayout_expandable_spinner_size, spinnerSize) this.spinnerMargin = - a.getDimension(R.styleable.ExpandableLayout_expandable_spinner_margin, this.spinnerMargin) + a.getDimension(R.styleable.ExpandableLayout_expandable_spinner_margin, spinnerMargin) this.spinnerColor = - a.getColor(R.styleable.ExpandableLayout_expandable_spinner_color, this.spinnerColor) + a.getColor(R.styleable.ExpandableLayout_expandable_spinner_color, spinnerColor) this.isExpanded = - a.getBoolean(R.styleable.ExpandableLayout_expandable_isExpanded, this.isExpanded) + a.getBoolean(R.styleable.ExpandableLayout_expandable_isExpanded, isExpanded) } override fun onFinishInflate() { @@ -169,18 +170,20 @@ class ExpandableLayout : FrameLayout { private fun updateParentLayout() { this.parentFrameLayout = inflate(R.layout.expandable_layout_parent) as RelativeLayout - this.parentLayout = inflate(this.parentLayoutResource) + this.parentLayout = inflate(parentLayoutResource) this.parentLayout.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) - this.parentFrameLayout.cover.addView(this.parentLayout) + this.parentFrameLayout.cover.addView(parentLayout) this.parentFrameLayout.cover.updateLayoutParams { height = parentLayout.measuredHeight } - addView(this.parentFrameLayout) + addView(parentFrameLayout) } private fun updateSecondLayout() { secondLayout = inflate(secondLayoutResource) + secondLayout.visible(false) addView(secondLayout) secondLayout.post { - secondLayoutHeight = setMeasureHeight(secondLayout) + secondLayoutHeight = getMeasuredHeight(secondLayout) + secondLayout.visible(true) with(secondLayout) { updateLayoutParams { height = 0 } y = parentLayout.measuredHeight.toFloat() @@ -208,13 +211,15 @@ class ExpandableLayout : FrameLayout { } } - private fun setMeasureHeight(parent: ViewGroup): Int { - var height = parent.height - for (i in 0 until parent.childCount) { - val child = parent.getChildAt(i) - if (child is ExpandableLayout) { - child.post { - height += setMeasureHeight(child) + private fun getMeasuredHeight(view: View): Int { + var height = view.height + if (view is ViewGroup) { + for (i in 0 until view.childCount) { + val child = view.getChildAt(i) + if (child is ExpandableLayout) { + child.post { + height += getMeasuredHeight(child) + } } } } @@ -289,15 +294,11 @@ class ExpandableLayout : FrameLayout { } } - private fun inflate(@LayoutRes resource: Int): ViewGroup { + private fun inflate(@LayoutRes resource: Int): View { val inflater: LayoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater val view = inflater.inflate(resource, this, false) - if (view is ViewGroup) { - return view - } else { - throw IllegalArgumentException("the layout resource should be wrapped a ViewGroup.") - } + return view } /** Builder class for creating [ExpandableLayout]. */