Skip to content
Snippets Groups Projects
Commit be3fefb1 authored by Nicolas Pomepuy's avatar Nicolas Pomepuy Committed by Geoffrey Métais
Browse files

Vertical seekbar improvement

parent cede5490
No related branches found
No related tags found
No related merge requests found
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="state"
type="org.videolan.vlc.gui.audio.EqualizerFragment.EqualizerState" />
......@@ -10,19 +12,19 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="320dp"
android:minWidth="448dp"
android:minHeight="320dp"
android:padding="@dimen/default_margin">
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/equalizer_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@+id/equalizer_preamp"
app:layout_constraintBottom_toBottomOf="@+id/equalizer_preamp"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/equalizer_presets"
app:layout_constraintHorizontal_chainStyle="spread_inside" />
app:layout_constraintTop_toTopOf="@+id/equalizer_preamp" />
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/equalizer_presets"
......@@ -34,46 +36,46 @@
app:layout_constraintTop_toTopOf="@+id/equalizer_preamp" />
<ImageView
android:visibility="@{state.saveButtonVisibility}"
android:id="@+id/equalizer_save"
android:layout_width="wrap_content"
android:layout_height="40dp"
app:layout_constraintWidth_min="wrap"
app:layout_constraintDimensionRatio="1"
android:src="?attr/ic_save"
app:layout_constraintTop_toTopOf="parent"
android:visibility="@{state.saveButtonVisibility}"
app:layout_constraintDimensionRatio="1"
app:layout_constraintLeft_toRightOf="@+id/equalizer_presets"
app:layout_constraintRight_toLeftOf="@+id/equalizer_revert"/>
app:layout_constraintRight_toLeftOf="@+id/equalizer_revert"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_min="wrap" />
<ImageView
android:visibility="@{state.revertButtonVisibility}"
android:id="@+id/equalizer_revert"
android:layout_width="wrap_content"
android:layout_height="40dp"
app:layout_constraintWidth_min="wrap"
app:layout_constraintDimensionRatio="1"
android:src="?attr/ic_reset"
app:layout_constraintTop_toTopOf="parent"
android:visibility="@{state.revertButtonVisibility}"
app:layout_constraintDimensionRatio="1"
app:layout_constraintLeft_toRightOf="@+id/equalizer_save"
app:layout_constraintRight_toLeftOf="@+id/guideine" />
app:layout_constraintRight_toLeftOf="@+id/guideine"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_min="wrap" />
<ImageView
android:visibility="@{state.deleteButtonVisibility}"
android:id="@+id/equalizer_delete"
android:layout_width="wrap_content"
android:layout_height="40dp"
app:layout_constraintWidth_min="wrap"
app:layout_constraintDimensionRatio="1"
android:src="?attr/ic_trash"
app:layout_constraintTop_toTopOf="@+id/equalizer_save"
android:visibility="@{state.deleteButtonVisibility}"
app:layout_constraintDimensionRatio="1"
app:layout_constraintLeft_toLeftOf="@+id/equalizer_save"
app:layout_constraintRight_toRightOf="@+id/equalizer_save" />
app:layout_constraintRight_toRightOf="@+id/equalizer_save"
app:layout_constraintTop_toTopOf="@+id/equalizer_save"
app:layout_constraintWidth_min="wrap" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideine"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5"
app:layout_constraintLeft_toRightOf="@+id/equalizer_revert"
app:layout_constraintRight_toLeftOf="@+id/equalizer_preamp" />
......@@ -85,33 +87,22 @@
android:maxHeight="4dip"
android:minHeight="4dip"
android:progressDrawable="@drawable/po_seekbar"
android:thumb="@drawable/seekbar_thumb"
android:splitTrack="false"
android:thumb="@drawable/seekbar_thumb"
app:layout_constraintBottom_toBottomOf="@+id/equalizer_revert"
app:layout_constraintTop_toTopOf="@+id/equalizer_revert"
app:layout_constraintLeft_toRightOf="@+id/guideine"
app:layout_constraintRight_toRightOf="parent" />
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/equalizer_revert" />
<HorizontalScrollView
android:id="@+id/equalizer_scroll"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintHorizontal_bias="0.5"
android:fillViewport="true"
android:fadeScrollbars="false"
app:layout_constraintTop_toBottomOf="@+id/equalizer_preamp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<LinearLayout
android:id="@+id/equalizer_bands"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</HorizontalScrollView>
<LinearLayout
android:id="@+id/equalizer_bands"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/kl_normal"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/equalizer_preamp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="state"
type="org.videolan.vlc.gui.audio.EqualizerFragment.EqualizerState" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="320dp"
android:padding="@dimen/default_margin" >
android:padding="@dimen/default_margin">
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/equalizer_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@+id/equalizer_save"
app:layout_constraintBottom_toBottomOf="@+id/equalizer_save"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintVertical_chainStyle="packed"/>
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="@+id/equalizer_save"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/equalizer_presets"
......@@ -37,42 +38,42 @@
app:layout_constraintWidth_min="wrap" />
<ImageView
android:visibility="@{state.saveButtonVisibility}"
android:id="@+id/equalizer_save"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:scaleType="centerInside"
app:layout_constraintWidth_min="wrap"
app:layout_constraintDimensionRatio="1"
android:src="?attr/ic_save"
app:layout_constraintTop_toTopOf="parent"
android:visibility="@{state.saveButtonVisibility}"
app:layout_constraintDimensionRatio="1"
app:layout_constraintLeft_toRightOf="@+id/equalizer_presets"
app:layout_constraintRight_toLeftOf="@+id/equalizer_revert"/>
app:layout_constraintRight_toLeftOf="@+id/equalizer_revert"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_min="wrap" />
<ImageView
android:visibility="@{state.revertButtonVisibility}"
android:id="@+id/equalizer_revert"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:scaleType="centerInside"
app:layout_constraintWidth_min="wrap"
app:layout_constraintDimensionRatio="1"
android:src="?attr/ic_reset"
app:layout_constraintTop_toTopOf="parent"
android:visibility="@{state.revertButtonVisibility}"
app:layout_constraintDimensionRatio="1"
app:layout_constraintLeft_toRightOf="@+id/equalizer_save"
app:layout_constraintRight_toRightOf="parent" />
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_min="wrap" />
<ImageView
android:visibility="@{state.deleteButtonVisibility}"
android:id="@+id/equalizer_delete"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:scaleType="centerInside"
app:layout_constraintDimensionRatio="1"
android:src="?attr/ic_trash"
app:layout_constraintTop_toTopOf="parent"
android:visibility="@{state.deleteButtonVisibility}"
app:layout_constraintDimensionRatio="1"
app:layout_constraintLeft_toLeftOf="@+id/equalizer_save"
app:layout_constraintRight_toRightOf="@+id/equalizer_save" />
app:layout_constraintRight_toRightOf="@+id/equalizer_save"
app:layout_constraintTop_toTopOf="parent" />
<SeekBar
android:id="@+id/equalizer_preamp"
......@@ -83,31 +84,20 @@
android:progressDrawable="@drawable/po_seekbar"
android:splitTrack="false"
android:thumb="@drawable/seekbar_thumb"
app:layout_constraintTop_toBottomOf="@+id/equalizer_save"
app:layout_constraintBottom_toTopOf="@+id/equalizer_scroll"
app:layout_constraintBottom_toTopOf="@+id/equalizer_bands"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/equalizer_save" />
<HorizontalScrollView
android:id="@+id/equalizer_scroll"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintHorizontal_bias="0.5"
android:fillViewport="true"
android:fadeScrollbars="false"
app:layout_constraintTop_toBottomOf="@+id/equalizer_preamp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<LinearLayout
android:id="@+id/equalizer_bands"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</HorizontalScrollView>
<LinearLayout
android:id="@+id/equalizer_bands"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/kl_normal"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/equalizer_preamp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/default_margin"
android:orientation="vertical" >
android:orientation="vertical">
<!-- Be careful: the view is rotated by 90 degrees. -->
<org.videolan.vlc.gui.view.VerticalSeekBar
android:id="@+id/equalizer_seek"
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:maxHeight="4dip"
android:minHeight="4dip"
android:progressDrawable="@drawable/po_seekbar"
android:thumb="@drawable/seekbar_thumb"
android:splitTrack="false"/>
android:text="+20dB"
android:textSize="10sp"
tools:ignore="HardcodedText" />
<org.videolan.vlc.gui.view.VerticalSeekBarContainer
android:layout_width="wrap_content"
android:layout_height="150dp">
<org.videolan.vlc.gui.view.VerticalSeekBar
android:id="@+id/equalizer_seek"
android:layout_width="0dp"
android:layout_height="0dp"
android:splitTrack="false"
android:thumb="@drawable/seekbar_thumb" />
</org.videolan.vlc.gui.view.VerticalSeekBarContainer>
<TextView
android:id="@+id/equalizer_band"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="12sp"
android:text="16 kHz"
android:text="-20dB"
android:textSize="10sp"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/equalizer_value"
android:id="@+id/equalizer_band"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="10dp"
android:textSize="12sp"
android:text="0.0 dB"
android:text="16kHz"
android:textSize="10sp"
tools:ignore="HardcodedText" />
</LinearLayout>
\ No newline at end of file
......@@ -31,9 +31,9 @@ import android.widget.*
import android.widget.AdapterView.OnItemSelectedListener
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableInt
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import org.videolan.libvlc.MediaPlayer
......@@ -41,6 +41,7 @@ import org.videolan.vlc.PlaybackService
import org.videolan.vlc.R
import org.videolan.vlc.VLCApplication
import org.videolan.vlc.databinding.EqualizerBinding
import org.videolan.vlc.gui.dialogs.VLCBottomSheetDialogFragment
import org.videolan.vlc.gui.helpers.UiTools
import org.videolan.vlc.gui.view.EqualizerBar
import org.videolan.vlc.interfaces.OnEqualizerBarChangeListener
......@@ -50,7 +51,12 @@ import java.util.*
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
class EqualizerFragment : AppCompatDialogFragment() {
class EqualizerFragment : VLCBottomSheetDialogFragment() {
override fun getDefaultState() = STATE_EXPANDED
override fun needToManageOrientation() = false
override fun initialFocusedView() = binding.equalizerBands.getChildAt(0)
private lateinit var equalizer: MediaPlayer.Equalizer
private var customCount = 0
......@@ -178,8 +184,8 @@ class EqualizerFragment : AppCompatDialogFragment() {
}
override fun onResume() {
super.onResume()
fillViews()
super.onResume()
}
override fun onPause() {
......@@ -254,11 +260,11 @@ class EqualizerFragment : AppCompatDialogFragment() {
.setPositiveButton(R.string.save, null)
.setNegativeButton(R.string.do_not_save) { _, _ ->
if (onPause)
VLCOptions.saveEqualizerInSettings(requireActivity(), equalizer, allSets[positionToSave], binding.equalizerButton.isChecked, false)
VLCOptions.saveEqualizerInSettings(VLCApplication.appContext, equalizer, allSets[positionToSave], binding.equalizerButton.isChecked, false)
}
.setOnCancelListener {
if (onPause)
VLCOptions.saveEqualizerInSettings(requireActivity(), equalizer, allSets[positionToSave], binding.equalizerButton.isChecked, false)
VLCOptions.saveEqualizerInSettings(VLCApplication.appContext, equalizer, allSets[positionToSave], binding.equalizerButton.isChecked, false)
}
.create()
val window = saveEqualizer.window
......
......@@ -30,25 +30,23 @@ import android.widget.LinearLayout
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import org.videolan.vlc.R
import org.videolan.vlc.interfaces.OnEqualizerBarChangeListener
class EqualizerBar : LinearLayout {
private var mSeek: VerticalSeekBar? = null
private var mBand: TextView? = null
private var mValue: TextView? = null
private lateinit var verticalSeekBar: VerticalSeekBar
private var bandTextView: TextView? = null
private var listener: OnEqualizerBarChangeListener? = null
private val mSeekListener = object : OnSeekBarChangeListener {
private val seekListener = object : OnSeekBarChangeListener {
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {}
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
val value = (progress - RANGE) / PRECISION.toFloat()
mValue!!.text = "$value dB"
if (listener != null) {
// HACK: VerticalSeekBar programmatically calls onProgress
// fromUser will always be false
......@@ -58,8 +56,6 @@ class EqualizerBar : LinearLayout {
}
}
private val fromUser: Boolean
get() = mSeek!!.fromUser
constructor(context: Context, band: Float) : super(context) {
init(context, band)
......@@ -73,22 +69,21 @@ class EqualizerBar : LinearLayout {
private fun init(context: Context, band: Float) {
LayoutInflater.from(context).inflate(R.layout.equalizer_bar, this, true)
mSeek = findViewById(R.id.equalizer_seek)
verticalSeekBar = findViewById(R.id.equalizer_seek)
//Force LTR to fix VerticalSeekBar background problem with RTL layout
mSeek!!.layoutDirection = View.LAYOUT_DIRECTION_LTR
mSeek!!.max = 2 * RANGE
mSeek!!.progress = RANGE
mSeek!!.setOnSeekBarChangeListener(mSeekListener)
mBand = findViewById(R.id.equalizer_band)
mBand!!.text = if (band < 999.5f)
(band + 0.5f).toInt().toString() + " Hz"
verticalSeekBar.layoutDirection = View.LAYOUT_DIRECTION_LTR
verticalSeekBar.max = 2 * RANGE
verticalSeekBar.progress = RANGE
verticalSeekBar.setOnSeekBarChangeListener(seekListener)
bandTextView = findViewById(R.id.equalizer_band)
bandTextView!!.text = if (band < 999.5f)
(band + 0.5f).toInt().toString() + "Hz"
else
(band / 1000.0f + 0.5f).toInt().toString() + " kHz"
mValue = findViewById(R.id.equalizer_value)
(band / 1000.0f + 0.5f).toInt().toString() + "kHz"
}
fun setValue(value: Float) {
mSeek!!.progress = (value * PRECISION + RANGE).toInt()
verticalSeekBar.progress = (value * PRECISION + RANGE).toInt()
}
fun setListener(listener: OnEqualizerBarChangeListener) {
......
/*****************************************************************************
* VerticalSeekBar.java
*
* Copyright © 2013 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*/
package org.videolan.vlc.gui.view
import android.content.Context
import android.graphics.Canvas
import android.os.Build
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatSeekBar
class VerticalSeekBar : AppCompatSeekBar {
private var mIsMovingThumb = false
var fromUser = false
constructor(context: Context) : super(context) {}
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(h, w, oldh, oldw)
}
@Synchronized
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec)
setMeasuredDimension(measuredHeight, measuredWidth)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
override fun onDraw(c: Canvas) {
c.rotate(-90f)
c.translate((-height).toFloat(), 0f)
val handled = super.onTouchEvent(event)
super.onDraw(c)
}
if (handled) {
when (event.action) {
MotionEvent.ACTION_DOWN -> parent?.requestDisallowInterceptTouchEvent(true)
override fun setProgress(progress: Int) {
super.setProgress(progress)
onSizeChanged(width, height, 0, 0)
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> parent?.requestDisallowInterceptTouchEvent(false)
}
}
private fun isWithinThumb(event: MotionEvent): Boolean {
val progress = progress.toFloat()
val density = this.resources.displayMetrics.density
val height = height.toFloat()
val y = event.y
val max = max.toFloat()
return progress >= max - (max * (y + THUMB_SLOP * density) / height).toInt() && progress <= max - (max * (y - THUMB_SLOP * density) / height).toInt()
return handled
}
override fun onTouchEvent(event: MotionEvent): Boolean {
if (!isEnabled) {
return false
}
var handled = false
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (isEnabled) {
when (event.action) {
MotionEvent.ACTION_DOWN -> if (isWithinThumb(event)) {
fromUser = true
parent.requestDisallowInterceptTouchEvent(true)
mIsMovingThumb = true
handled = true
}
MotionEvent.ACTION_MOVE -> if (mIsMovingThumb) {
val max = max
progress = max - (max * event.y / height).toInt()
handled = true
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
parent.requestDisallowInterceptTouchEvent(false)
mIsMovingThumb = false
handled = true
fromUser = false
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) return false
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP) {
val direction = if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) -1 else 1
var currentProgress = progress + (direction * keyProgressIncrement)
if (currentProgress > max) {
currentProgress = max
} else if (currentProgress < 0) {
currentProgress = 0
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) setProgress(currentProgress, true) else progress = currentProgress
return true
}
}
return handled
}
companion object {
private const val THUMB_SLOP = 25f
return super.onKeyDown(keyCode, event)
}
}
}
\ No newline at end of file
package org.videolan.vlc.gui.view
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
class VerticalSeekBarContainer @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) {
private val childSeekBar: VerticalSeekBar?
get() {
val child = if (childCount > 0) getChildAt(0) else null
return if (child is VerticalSeekBar) child else null
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
val seekBar = childSeekBar
if (seekBar != null) {
val hPadding = paddingLeft + paddingRight
val vPadding = paddingTop + paddingBottom
seekBar.measure(
MeasureSpec.makeMeasureSpec(Math.max(0, h - vPadding), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(Math.max(0, w - hPadding), MeasureSpec.AT_MOST))
}
applyViewRotation(w, h)
super.onSizeChanged(w, h, oldw, oldh)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val seekBar = childSeekBar
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
if (seekBar != null && widthMode != MeasureSpec.EXACTLY) {
val seekBarWidth: Int = seekBar.measuredHeight
val seekBarHeight: Int = seekBar.measuredWidth
val hPadding = paddingLeft + paddingRight
val vPadding = paddingTop + paddingBottom
val innerContentWidthMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(0, widthSize - hPadding), widthMode)
val innerContentHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(0, heightSize - vPadding), heightMode)
seekBar.measure(innerContentHeightMeasureSpec, innerContentWidthMeasureSpec)
val measuredWidth = View.resolveSizeAndState(seekBarWidth + hPadding, widthMeasureSpec, 0)
val measuredHeight = View.resolveSizeAndState(seekBarHeight + vPadding, heightMeasureSpec, 0)
setMeasuredDimension(measuredWidth, measuredHeight)
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}
private fun applyViewRotation(w: Int, h: Int) {
val seekBar = childSeekBar
layoutDirection = View.LAYOUT_DIRECTION_LTR
if (seekBar != null) {
val seekBarMeasuredWidth = seekBar.measuredWidth
val seekBarMeasuredHeight = seekBar.measuredHeight
val hPadding = paddingLeft + paddingRight
val vPadding = paddingTop + paddingBottom
val hOffset = (Math.max(0, w - hPadding) - seekBarMeasuredHeight) / 2f
val lp = seekBar.layoutParams
lp.width = Math.max(0, h - vPadding)
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT
seekBar.layoutParams = lp
seekBar.pivotX = 0f
seekBar.pivotY = 0f
seekBar.rotation = 270f
seekBar.translationX = hOffset
seekBar.translationY = seekBarMeasuredWidth.toFloat()
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment