{
15 | constructor() : super()
16 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
17 | var peekHeightListener: OnPeekHeightListener? = null
18 |
19 | @ColorInt
20 | private var contentColor: Int = 0
21 |
22 | @ColorInt
23 | private var headerColor: Int = 0
24 |
25 | private var container: FrameLayout? = null
26 | private var header: View? = null
27 | private var content: View? = null
28 |
29 | private var bottomInset: Int = 0
30 | private var topInset: Int = 0
31 |
32 | override fun initLayoutChild(view: V) {
33 | super.initLayoutChild(view)
34 | header = view.header
35 | content = view.content
36 | container = view.container
37 | contentColor = view.contentColor
38 | headerColor = view.headerColor
39 | topInset = view.topInset
40 | bottomInset = view.bottomInset
41 |
42 | val height = header?.height ?: 0
43 | val width = header?.width ?: 0
44 | if (peekHeight == PEEK_HEIGHT_AUTO) {
45 | peekHeight = height + bottomInset
46 | }
47 | if (expandedWidth == 0) {
48 | expandedWidth = width
49 | }
50 | onPeekHeightChanged(peekHeight)
51 | sheetBackground?.tintList = null
52 | onStartState()
53 | }
54 |
55 | private fun onStartState() {
56 | if (state == BottomSheetBehavior.STATE_HALF_EXPANDED || state == BottomSheetBehavior.STATE_EXPANDED) {
57 | container?.alpha = 1f
58 | header?.alpha = 0f
59 | sheetBackground?.fillColor = ColorStateList.valueOf(contentColor)
60 | sheetBackground?.interpolation = 0f
61 | header?.visibility = View.GONE
62 | content?.visibility = View.VISIBLE
63 | if(state != BottomSheetBehavior.STATE_HALF_EXPANDED) {
64 | container?.translationY = topInset.toFloat()
65 | }
66 | } else {
67 | sheetBackground?.fillColor = ColorStateList.valueOf(headerColor)
68 | header?.visibility = View.VISIBLE
69 | content?.visibility = View.GONE
70 | container?.alpha = 0f
71 | header?.alpha = 1f
72 | content?.visibility = View.GONE
73 | }
74 | }
75 |
76 | override fun internalOnSlide(slideOffset: Float) {
77 | super.internalOnSlide(slideOffset)
78 | sheetBackground?.interpolation =
79 | interpolate(
80 | 1f,
81 | 0f,
82 | 0f,
83 | 0.15f,
84 | slideOffset
85 | )
86 | sheetBackground?.fillColor = ColorStateList.valueOf(
87 | interpolateArgb(
88 | headerColor,
89 | contentColor,
90 | 0f,
91 | halfExpandedRatio,
92 | slideOffset
93 | )
94 | )
95 |
96 | header?.alpha = interpolate(
97 | 1f,
98 | 0f,
99 | 0f,
100 | 0.15f,
101 | slideOffset
102 | )
103 | header?.visibility = if (slideOffset < 0.5) View.VISIBLE else View.GONE
104 | content?.visibility = if (slideOffset > 0.2) View.VISIBLE else View.GONE
105 | container?.alpha = interpolate(
106 | 0f,
107 | 1f,
108 | 0.2f,
109 | halfExpandedRatio - 0.1f,
110 | slideOffset
111 | )
112 |
113 | container?.translationY = interpolate(
114 | 0f,
115 | topInset.toFloat(),
116 | halfExpandedRatio - 0.1f,
117 | 1f,
118 | slideOffset
119 | )
120 | }
121 |
122 | fun onPeekHeightChanged(newPeekHeight: Int) {
123 | peekHeightListener?.onPeekHeightChanged(newPeekHeight)
124 | }
125 |
126 | interface OnPeekHeightListener {
127 | fun onPeekHeightChanged(newPeekHeight: Int)
128 | }
129 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
22 |
23 |
30 |
31 |
35 |
36 |
41 |
42 |
49 |
50 |
59 |
60 |
61 |
62 |
68 |
69 |
74 |
75 |
80 |
81 |
86 |
87 |
88 |
89 |
90 |
104 |
105 |
113 |
114 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Corner Sheet
2 | Behavior to make a view expands from corner
3 | 
4 |
5 | ## Usage
6 |
7 | The usage is similar to [BottomSheetBehavior](https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior)
8 | Corner Sheet - behavior that allow you expand a view from corner.
9 |
10 | 
11 | A simple view with behavior in xml will be look like:
12 |
13 | ```xml
14 |
18 |
19 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 | ```
43 |
44 | You can use the following attributes on view with CornerSheetBehavior.
45 |
46 | | Properties | Type | Default |
47 | | -------------------------------------------| --------------------- | ------- |
48 | | `behavior_horizontalExpandingRatio` | float | 0.2f |
49 | | `behavior_expanded_width` | dimension | 0dp |
50 | | `behavior_horizontal_peekHeight` | dimension | 0dp |
51 |
52 | Customize corner shape with `shapeAppearanceOverlay` attribute:
53 | ```xml
54 |
58 | ```
59 |
60 | There are 3 state of CornerSheetBehavior:
61 |
62 | | State | Description |
63 | | --------------------------------------| -------------------------------------------------------------------- |
64 | | `CornerSheetBehavior.STATE_EXPANDED` | expanded horizontally on `behavior_expanded_width` value |
65 | | `CornerSheetBehavior.STATE_COLLAPSED` | expanded horizontally on `behavior_horizontal_peekHeight` value |
66 | | `CornerSheetBehavior.STATE_HIDDEN` | hide horizontally |
67 |
68 | 
69 |
70 | There are following api that can be used on `CornerSheetBehavior`:
71 | ```kotlin
72 | behavior.expandingRatio = 0.5f
73 | behavior.horizontalState = CornerSheetBehavior.STATE_EXPANDED
74 | behavior.expandedWidth = 170.dp()
75 | behavior.setHorizontalPeekHeight(60.dp(), animate = true) //will be animated if horizontal state is CornerSheetBehavior.STATE_COLLAPSED
76 | ```
77 |
78 | Just check app module with "Behavior Sample":
79 |
80 | 
81 |
82 |
83 | There is also an option to use a view that can contain a header and content:
84 |
85 | ```xml
86 |
90 |
91 |
103 |
104 | ```
105 |
106 | With CornerDrawer you don't need to set `behavior_peekHeight` and `behavior_expanded_width`, they will be assigned automatically when `header_view` will be inflated.
107 |
108 | You can use an attributes on behavior that described below and a following attributes on CornerDrawer
109 |
110 | | Properties | Type | Default |
111 | | ------------------- | ------------ | ------- |
112 | | `header_view` | reference | -1 |
113 | | `header_color` | reference | #FFF |
114 | | `content_view` | reference | -1 |
115 | | `content_color` | reference | #FFF |
116 |
117 | The main preview is done with `CornerDrawer`, just check app module with "Support Sample"
118 |
119 | ## Integration
120 |
121 | This library is available on **mavenCentral**, so you need to add this repository to your root build.gradle:
122 |
123 | ```groovy
124 | allprojects {
125 | repositories {
126 | ...
127 | mavenCentral()
128 | }
129 | }
130 | ```
131 |
132 | Add one of the following dependency:
133 |
134 | ```groovy
135 | dependencies {
136 |
137 | //only CornerSheetBehavior
138 | implementation 'com.github.heyalex.cornersheet:core:v1.0.1'
139 |
140 | //CornerSheetBehavior and CornerDrawer
141 | implementation 'com.github.heyalex.cornersheet:drawer:v1.0.1'
142 | }
143 | ```
144 |
145 | ## Samples
146 | You can find sample in app module, to understand functionality of library or just get an APK [here](https://github.com/HeyAlex/CornerSheet/raw/master/raw/app-debug.apk)
147 |
--------------------------------------------------------------------------------
/core/src/main/java/com/google/android/material/bottomsheet/CornerMaterialSheetBehavior.kt:
--------------------------------------------------------------------------------
1 | package com.google.android.material.bottomsheet
2 |
3 | import android.animation.ValueAnimator
4 | import android.content.Context
5 | import android.content.res.ColorStateList
6 | import android.content.res.TypedArray
7 | import android.os.Parcel
8 | import android.os.Parcelable
9 | import android.util.AttributeSet
10 | import android.util.TypedValue
11 | import android.view.MotionEvent
12 | import android.view.View
13 | import android.view.animation.AccelerateInterpolator
14 | import androidx.annotation.FloatRange
15 | import androidx.annotation.IntDef
16 | import androidx.annotation.StyleableRes
17 | import androidx.appcompat.content.res.AppCompatResources
18 | import androidx.coordinatorlayout.widget.CoordinatorLayout
19 | import androidx.core.view.ViewCompat
20 | import com.github.heyalex.cornersheet.R
21 | import com.github.heyalex.cornersheet.behavior.CornerSheetBehavior
22 | import com.github.heyalex.cornersheet.interpolate
23 | import com.google.android.material.shape.MaterialShapeDrawable
24 | import com.google.android.material.shape.ShapeAppearanceModel
25 |
26 | /**
27 | * An inheritor of BottomSheetBehavior
28 | *
29 | * Changing translation X depends on slide offset of BottomSheetBehavior
30 | *
31 | * This class is in com.google.android.material.bottomsheet package,
32 | * since we need access to internal field like "viewRef"
33 | * and fetching style attr like "backgroundTint"
34 | */
35 | open class CornerMaterialSheetBehavior : BottomSheetBehavior {
36 |
37 | private var fullViewWidth: Int = 0
38 | private var currentWidth: Int = 0
39 | private var horizontalPeekWidth: Int = 0
40 |
41 | var horizontalState: Int = CornerSheetBehavior.STATE_COLLAPSED
42 | set(value) {
43 | if (field == value) return
44 |
45 | field = value
46 | if (state != STATE_EXPANDED) {
47 | getView {
48 | startAnimation(it)
49 | }
50 | }
51 | }
52 |
53 | @FloatRange(from = 0.0, to = 1.0)
54 | var expandingRatio: Float = 0f
55 |
56 | var expandedWidth: Int = 0
57 |
58 | private var isViewRefInitialized: Boolean = false
59 | protected var sheetBackground: MaterialShapeDrawable? = null
60 |
61 | constructor() : super()
62 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
63 | val typedArray =
64 | context.obtainStyledAttributes(attrs, R.styleable.CornerSheetBehavior_Layout)
65 | horizontalPeekWidth = typedArray.getDimensionPixelSize(
66 | R.styleable.CornerSheetBehavior_Layout_behavior_horizontal_peekHeight,
67 | -1
68 | )
69 |
70 | expandingRatio = typedArray.getFloat(
71 | R.styleable.CornerSheetBehavior_Layout_behavior_horizontalExpandingRatio,
72 | 0.2f
73 | )
74 |
75 | expandedWidth = typedArray.getDimensionPixelSize(
76 | R.styleable.CornerSheetBehavior_Layout_behavior_expanded_width,
77 | 0
78 | )
79 |
80 | sheetBackground = MaterialShapeDrawable(
81 | ShapeAppearanceModel.builder(
82 | context,
83 | attrs,
84 | R.attr.bottomSheetStyle,
85 | 0
86 | ).build()
87 | )
88 |
89 | val typedArrayBottomSheet =
90 | context.obtainStyledAttributes(attrs, R.styleable.BottomSheetBehavior_Layout)
91 |
92 | val bottomSheetColor =
93 | getColorStateList(
94 | context,
95 | typedArrayBottomSheet,
96 | R.styleable.BottomSheetBehavior_Layout_backgroundTint
97 | )
98 |
99 | typedArrayBottomSheet.recycle()
100 | if (bottomSheetColor != null) {
101 | sheetBackground?.fillColor = bottomSheetColor
102 | } else {
103 | val defaultColor = TypedValue()
104 | context.theme.resolveAttribute(android.R.attr.colorBackground, defaultColor, true)
105 | sheetBackground?.setTint(defaultColor.data)
106 | }
107 |
108 | typedArray.recycle()
109 | }
110 |
111 | fun setHorizontalPeekHeight(width: Int, animate: Boolean) {
112 | horizontalPeekWidth = width
113 | getView {
114 |
115 | if (state == STATE_COLLAPSED && horizontalState == CornerSheetBehavior.STATE_COLLAPSED) {
116 | if (animate) {
117 | startAnimation(it)
118 | } else {
119 | it.translationX = horizontalPeekWidth.toFloat()
120 | }
121 | }
122 | }
123 | }
124 |
125 | private fun getView(unit: ((V) -> Unit)) {
126 | viewRef?.get()?.let {
127 | unit.invoke(it)
128 | }
129 | }
130 |
131 | override fun onLayoutChild(parent: CoordinatorLayout, child: V, layoutDirection: Int): Boolean {
132 | val onLayoutChildResult = super.onLayoutChild(parent, child, layoutDirection)
133 | if (!isViewRefInitialized) {
134 | ViewCompat.setBackground(child, sheetBackground)
135 | fullViewWidth = child.width
136 | currentWidth = getMaxWidthCornerSheet()
137 | if (state == STATE_EXPANDED || state == STATE_HALF_EXPANDED) {
138 | child.translationX = 0f
139 | sheetBackground?.interpolation = 0f
140 | } else {
141 | child.translationX = currentWidth.toFloat()
142 | sheetBackground?.interpolation = 1f
143 | }
144 | initLayoutChild(child)
145 | addBottomSheetCallback(object :
146 | BottomSheetCallback() {
147 | override fun onSlide(bottomSheet: View, slideOffset: Float) {
148 | val translationValue = getMaxWidthCornerSheet()
149 | child.translationX =
150 | interpolate(
151 | translationValue.toFloat(),
152 | 0f,
153 | 0f,
154 | expandingRatio,
155 | slideOffset
156 | )
157 | sheetBackground?.interpolation =
158 | interpolate(
159 | 1f,
160 | 0f,
161 | 0f,
162 | expandingRatio,
163 | slideOffset
164 | )
165 | internalOnSlide(slideOffset)
166 | }
167 |
168 | override fun onStateChanged(bottomSheet: View, newState: Int) {
169 | }
170 | })
171 |
172 | isViewRefInitialized = true
173 | }
174 |
175 | return onLayoutChildResult
176 | }
177 |
178 | /** Callback for listen slideOffset internally **/
179 | open fun internalOnSlide(slideOffset: Float) {}
180 |
181 | /** Callback for listen for first layout child **/
182 | open fun initLayoutChild(view: V) {}
183 |
184 | override fun onTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
185 | return if (state != STATE_EXPANDED && event.x < child.translationX && state != STATE_DRAGGING) {
186 | false
187 | } else {
188 | super.onTouchEvent(parent, child, event)
189 | }
190 | }
191 |
192 | private fun startAnimation(view: V) {
193 | ValueAnimator.ofFloat(0f, 1f).apply {
194 | interpolator = AccelerateInterpolator()
195 | duration = 150
196 | val start = currentWidth
197 | val end = getMaxWidthCornerSheet()
198 |
199 | addUpdateListener { animation ->
200 | val value = animation.animatedValue as Float
201 | val lerp = interpolate(
202 | start.toFloat(),
203 | end.toFloat(),
204 | 0f,
205 | 1f,
206 | value
207 | )
208 | view.translationX = lerp
209 |
210 | }
211 |
212 | currentWidth = end
213 | }.start()
214 | }
215 |
216 | override fun onSaveInstanceState(parent: CoordinatorLayout, child: V): Parcelable {
217 | return CornerSavedState(super.onSaveInstanceState(parent, child), this)
218 | }
219 |
220 | override fun onRestoreInstanceState(
221 | parent: CoordinatorLayout, child: V, state: Parcelable
222 | ) {
223 | val ss = state as CornerSavedState
224 | super.onRestoreInstanceState(parent, child, ss.superState!!)
225 | this.horizontalState = ss.horizontalState
226 | this.horizontalPeekWidth = ss.horizontalPeekHeight
227 | this.expandedWidth = ss.expandedWidth
228 | }
229 |
230 | protected class CornerSavedState : SavedState {
231 |
232 | @HorizontalState
233 | internal val horizontalState: Int
234 | internal var horizontalPeekHeight: Int = 0
235 | internal var expandedWidth: Int = 0
236 |
237 | constructor(source: Parcel, horizontalState: Int) : super(source, null) {
238 | this.horizontalState = horizontalState
239 | }
240 |
241 | constructor(source: Parcel, loader: ClassLoader?) : super(source, loader) {
242 | horizontalState = source.readInt()
243 | horizontalPeekHeight = source.readInt()
244 | expandedWidth = source.readInt()
245 | }
246 |
247 | constructor(superState: Parcelable, behavior: CornerMaterialSheetBehavior<*>) : super(
248 | superState,
249 | behavior
250 | ) {
251 | this.horizontalState = behavior.horizontalState
252 | this.horizontalPeekHeight = behavior.horizontalPeekWidth
253 | this.expandedWidth = behavior.expandedWidth
254 | }
255 |
256 | @Deprecated("Use {@link SavedState(Parcelable, CornerMaterialSheetBehavior)} instead.")
257 | constructor(superstate: Parcelable, state: Int) : super(superstate, state) {
258 | this.horizontalState = state
259 | }
260 |
261 | override fun writeToParcel(out: Parcel, flags: Int) {
262 | super.writeToParcel(out, flags)
263 | out.writeInt(horizontalState)
264 | out.writeInt(horizontalPeekHeight)
265 | out.writeInt(expandedWidth)
266 | }
267 |
268 | override fun describeContents(): Int {
269 | return 0
270 | }
271 |
272 | companion object CREATOR : Parcelable.ClassLoaderCreator {
273 | override fun createFromParcel(`in`: Parcel, loader: ClassLoader): CornerSavedState {
274 | return CornerSavedState(`in`, loader)
275 | }
276 |
277 | override fun createFromParcel(`in`: Parcel): CornerSavedState? {
278 | return CornerSavedState(`in`, null)
279 | }
280 |
281 | override fun newArray(size: Int): Array {
282 | return arrayOfNulls(size)
283 | }
284 | }
285 | }
286 |
287 | override fun onAttachedToLayoutParams(layoutParams: CoordinatorLayout.LayoutParams) {
288 | super.onAttachedToLayoutParams(layoutParams)
289 | isViewRefInitialized = false
290 | }
291 |
292 | override fun onDetachedFromLayoutParams() {
293 | super.onDetachedFromLayoutParams()
294 | isViewRefInitialized = false
295 | }
296 |
297 | private fun getMaxWidthCornerSheet(): Int {
298 | val width = when (horizontalState) {
299 | CornerSheetBehavior.STATE_EXPANDED -> expandedWidth
300 | CornerSheetBehavior.STATE_COLLAPSED -> horizontalPeekWidth
301 | CornerSheetBehavior.STATE_HIDDEN -> 0
302 | else -> return 0
303 | }
304 | return fullViewWidth - width
305 | }
306 |
307 | @IntDef(
308 | CornerSheetBehavior.STATE_EXPANDED,
309 | CornerSheetBehavior.STATE_COLLAPSED,
310 | CornerSheetBehavior.STATE_HIDDEN
311 | )
312 | @Retention(AnnotationRetention.SOURCE)
313 | annotation class HorizontalState
314 |
315 | companion object {
316 |
317 | fun getColorStateList(
318 | context: Context, attributes: TypedArray, @StyleableRes index: Int
319 | ): ColorStateList? {
320 | if (attributes.hasValue(index)) {
321 | val resourceId = attributes.getResourceId(index, 0)
322 | if (resourceId != 0) {
323 | val value =
324 | AppCompatResources.getColorStateList(context, resourceId)
325 | if (value != null) {
326 | return value
327 | }
328 | }
329 | }
330 | return attributes.getColorStateList(index)
331 | }
332 | }
333 | }
334 |
--------------------------------------------------------------------------------