View RotaryKnobView.kt
override fun onTouchEvent(event: MotionEvent): Boolean { | |
return if (gestureDetector.onTouchEvent(event)) | |
true | |
else | |
super.onTouchEvent(event) | |
} | |
override fun onDown(event: MotionEvent): Boolean { | |
return true | |
} |
View MainActivity.kt
package geva.oren.rotaryknobdemo | |
import androidx.appcompat.app.AppCompatActivity | |
import android.os.Bundle | |
import kotlinx.android.synthetic.main.activity_main.* | |
class MainActivity : AppCompatActivity(), RotaryKnobView.RotaryKnobListener { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) |
View activity_main.xml
<geva.oren.rotaryknobdemo.RotaryKnobView | |
android:id="@+id/knob" | |
class="geva.oren.rotaryknobdemo.RotaryKnobView" | |
android:layout_width="@dimen/knob_width" | |
android:layout_height="@dimen/knob_height" | |
android:layout_marginBottom="312dp" | |
app:layout_constraintBottom_toBottomOf="parent" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintTop_toBottomOf="@+id/textView" |
View RotaryKnobView.kt
private fun setKnobPosition(angle: Float) { | |
val matrix = Matrix() | |
knobImageView.scaleType = ScaleType.MATRIX | |
matrix.postRotate(angle, width.toFloat() / 2, height.toFloat() / 2) | |
knobImageView.imageMatrix = matrix | |
} |
View RotaryKnobView.kt
private fun calculateAngle(x: Float, y: Float): Float { | |
val px = (x / width.toFloat()) - 0.5 | |
val py = ( 1 - y / height.toFloat()) - 0.5 | |
var angle = -(Math.toDegrees(atan2(py, px))) | |
.toFloat() + 90 | |
if (angle > 180) angle -= 360 | |
return angle | |
} |
View RotaryKnobView.kt
interface RotaryKnobListener { | |
fun onRotate(value: Int) | |
} |
View RotaryKnobView.kt
init { | |
this.maxValue = maxValue + 1 | |
LayoutInflater.from(context) | |
.inflate(R.layout.rotary_knob_view, this, true) | |
context.theme.obtainStyledAttributes( | |
attrs, | |
R.styleable.RotaryKnobView, | |
0, |
View RotaryKnobView.kt
class RotaryKnobView @JvmOverloads constructor( | |
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 | |
) : RelativeLayout(context, attrs, defStyleAttr), GestureDetector.OnGestureListener { | |
private val gestureDetector: GestureDetectorCompat | |
private var maxValue = 99 | |
private var minValue = 0 | |
var listener: RotaryKnobListener? = null | |
var value = 50 | |
private var knobDrawable: Drawable? = null | |
private var divider = 300f / (maxValue - minValue) |
View RotaryKnobView.kt
override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float) | |
: Boolean { | |
val rotationDegrees = calculateAngle(e2.x, e2.y) | |
// use only -150 to 150 range (knob min/max points | |
if (rotationDegrees >= -150 && rotationDegrees <= 150) { | |
setKnobPosition(rotationDegrees) | |
// Calculate rotary value | |
// The range is the 300 degrees between -150 and 150, so we'll add 150 to adjust the |
View RotaryKnobView.kt
override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float) | |
: Boolean { | |
return true | |
} | |
override fun onTouchEvent(event: MotionEvent): Boolean { | |
return if (gestureDetector.onTouchEvent(event)) | |
true | |
else | |
super.onTouchEvent(event) |
NewerOlder