Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package by.stylesoft.myapplication
- import android.content.Context
- import android.graphics.Rect
- import android.util.AttributeSet
- import android.view.LayoutInflater
- import android.view.View
- import android.view.ViewGroup
- class ExpansionPanel @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0,
- defStyleRes: Int = 0
- ) : ViewGroup(context, attrs, defStyleAttr, defStyleRes) {
- var headerView: View? = null
- set(value) {
- field?.let { removeView(it) }
- field = value
- field?.let {
- addView(it, 0)
- }
- }
- var contentView: View? = null
- set(value) {
- field?.let { removeView(it) }
- field = value
- field?.let { addView(it, 0) }
- }
- var isExpanded: Boolean = false
- private set
- private var lastWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
- private var lastHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
- init {
- attrs?.let {
- val typedArray = context.obtainStyledAttributes(
- it,
- R.styleable.ExpansionPanel,
- defStyleAttr,
- defStyleRes
- )
- headerView = inflate(typedArray.getResourceId(
- R.styleable.ExpansionPanel_ep_header_layout,
- LAYOUT_DEFAULT
- ))
- contentView = inflate(typedArray.getResourceId(
- R.styleable.ExpansionPanel_ep_content_layout,
- LAYOUT_DEFAULT
- ))
- isExpanded = typedArray.getBoolean(R.styleable.ExpansionPanel_ep_expanded, false)
- typedArray.recycle()
- }
- removeAllViews()
- headerView?.let { super.addView(it, 0) }
- contentView?.let { super.addView(it, 1) }
- }
- override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
- lastWidthMeasureSpec = widthMeasureSpec
- lastHeightMeasureSpec = heightMeasureSpec
- var desiredWidth = suggestedMinimumWidth +
- Math.max(paddingStart, paddingLeft) +
- Math.max(paddingEnd, paddingRight)
- var desiredHeight = suggestedMinimumHeight + paddingTop + paddingBottom
- headerView?.apply {
- val headerWidthMeasureSpec = calculateMeasureSpec(widthMeasureSpec, desiredWidth)
- val headerHeightMeasureSpec = calculateMeasureSpec(heightMeasureSpec, desiredHeight)
- measure(headerWidthMeasureSpec, headerHeightMeasureSpec)
- desiredWidth += measuredWidth
- desiredHeight += measuredHeight
- }
- if (isExpanded) {
- contentView?.apply {
- val headerWidth = headerView?.measuredWidth ?: 0
- val contentWidthMeasureSpec = MeasureSpec.makeMeasureSpec(headerWidth, MeasureSpec.EXACTLY)
- val contentHeightMeasureSpec = calculateMeasureSpec(heightMeasureSpec, desiredHeight)
- measure(contentWidthMeasureSpec, contentHeightMeasureSpec)
- desiredHeight += measuredHeight
- }
- }
- setMeasuredDimension(
- measureDimension(desiredWidth, widthMeasureSpec),
- measureDimension(desiredHeight, heightMeasureSpec)
- )
- }
- override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
- val bound = calculateBound(left, top, right, bottom)
- val contentTop = headerView?.let { hv ->
- val headerBottom = bound.top + hv.measuredHeight
- hv.layout(bound.left, bound.top, bound.right, headerBottom)
- headerBottom
- } ?: bound.top
- contentView?.layout(bound.left, contentTop, bound.right, bound.bottom)
- }
- fun setExpanded(expanded: Boolean, animate: Boolean = true) {
- isExpanded = expanded
- requestLayout()
- }
- private fun measureDimension(desiredSize: Int, measureSpec: Int): Int {
- val mode = MeasureSpec.getMode(measureSpec)
- val size = MeasureSpec.getSize(measureSpec)
- return when (mode) {
- MeasureSpec.EXACTLY -> size
- MeasureSpec.AT_MOST -> Math.min(desiredSize, size)
- MeasureSpec.UNSPECIFIED -> desiredSize
- else -> throw IllegalArgumentException("Unknown measure spec")
- }
- }
- private fun calculateMeasureSpec(measureSpec: Int, padding: Int): Int {
- val mode = MeasureSpec.getMode(measureSpec)
- val size = MeasureSpec.getSize(measureSpec)
- return when (mode) {
- MeasureSpec.EXACTLY, MeasureSpec.AT_MOST ->
- MeasureSpec.makeMeasureSpec(size - padding, mode)
- MeasureSpec.UNSPECIFIED ->
- MeasureSpec.makeMeasureSpec(size, mode)
- else -> throw IllegalArgumentException("Unknown measure spec mode: $mode")
- }
- }
- private fun calculateBound(left: Int, top: Int, right: Int, bottom: Int): Rect {
- val backgroundPadding = getBackgroundPadding()
- return Rect(
- left + backgroundPadding.left + Math.max(paddingStart, paddingLeft),
- top + backgroundPadding.top + paddingTop,
- right - backgroundPadding.right - Math.max(paddingEnd, paddingStart),
- bottom - backgroundPadding.bottom - paddingBottom
- )
- }
- private fun getBackgroundPadding() = Rect().apply { background?.getPadding(this) }
- private fun inflate(layout: Int): View? {
- return if (layout != LAYOUT_DEFAULT) {
- LayoutInflater.from(context).inflate(layout, this, false)
- } else {
- null
- }
- }
- companion object {
- val LAYOUT_DEFAULT = -1
- }
- }
Add Comment
Please, Sign In to add comment