Kotlin to Java Conversion: RangeSeekBarView Class
/*
- MIT License
- Copyright (c) 2016 Knowledge, education for life.
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the 'Software'), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE. */ package com.lb.video_trimmer_library.view;
import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View;
import androidx.annotation.ColorInt;
import com.lb.video_trimmer_library.interfaces.OnRangeSeekBarListener;
import java.util.HashSet;
public class RangeSeekBarView extends View { public enum ThumbType { LEFT(0), RIGHT(1);
private final int index;
ThumbType(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
}
private final float thumbTouchExtraMultiplier = initThumbTouchExtraMultiplier();
private final Thumb[] thumbs = {new Thumb(ThumbType.LEFT.getIndex()), new Thumb(ThumbType.RIGHT.getIndex())};
private final HashSet<OnRangeSeekBarListener> listeners = new HashSet<>();
private float maxWidth;
private final int thumbWidth = initThumbWidth(getContext());
private int viewWidth;
private float pixelRangeMin;
private float pixelRangeMax;
private final float scaleRangeMax = 100f;
private boolean firstRun = true;
private final Paint shadowPaint = new Paint();
private final Paint strokePaint = new Paint();
private final Paint edgePaint = new Paint();
private int currentThumb = ThumbType.LEFT.getIndex();
public RangeSeekBarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setFocusable(true);
setFocusableInTouchMode(true);
shadowPaint.setAntiAlias(true);
shadowPaint.setColor(initShadowColor());
strokePaint.setAntiAlias(true);
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, context.getResources().getDisplayMetrics()));
strokePaint.setColor(0xffffffff);
edgePaint.setAntiAlias(true);
edgePaint.setColor(0xffffffff);
}
public RangeSeekBarView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RangeSeekBarView(Context context) {
this(context, null);
}
@ColorInt
protected int initShadowColor() {
return 0xB1000000;
}
protected float initThumbTouchExtraMultiplier() {
return 1.0f;
}
protected int initThumbWidth(Context context) {
return Math.max((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 27f, context.getResources().getDisplayMetrics()), 1);
}
public void initMaxWidth() {
maxWidth = thumbs[ThumbType.RIGHT.getIndex()].pos - thumbs[ThumbType.LEFT.getIndex()].pos;
onSeekStop(this, ThumbType.LEFT.getIndex(), thumbs[ThumbType.LEFT.getIndex()].value);
onSeekStop(this, ThumbType.RIGHT.getIndex(), thumbs[ThumbType.RIGHT.getIndex()].value);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = getMeasuredWidth();
pixelRangeMin = 0f;
pixelRangeMax = viewWidth - thumbWidth;
if (firstRun) {
for (Thumb thumb : thumbs) {
thumb.value = scaleRangeMax * thumb.index;
thumb.pos = pixelRangeMax * thumb.index;
}
// Fire listener callback
onCreate(this, currentThumb, getThumbValue(currentThumb));
firstRun = false;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (thumbs.length == 0) {
return;
}
// draw shadows outside of selected range
for (Thumb thumb : thumbs) {
if (thumb.index == ThumbType.LEFT.getIndex()) {
float x = thumb.pos + getPaddingLeft();
if (x > pixelRangeMin) {
canvas.drawRect(thumbWidth, 0f, x + thumbWidth, getHeight(), shadowPaint);
}
} else {
float x = thumb.pos - getPaddingRight();
if (x < pixelRangeMax) {
canvas.drawRect(x, 0f, viewWidth - thumbWidth, getHeight(), shadowPaint);
}
}
}
// draw stroke around selected range
canvas.drawRect(thumbs[ThumbType.LEFT.getIndex()].pos + getPaddingLeft() + thumbWidth, 0f,
thumbs[ThumbType.RIGHT.getIndex()].pos - getPaddingRight(), getHeight(), strokePaint);
// draw edges
float circleRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6f, getContext().getResources().getDisplayMetrics());
canvas.drawCircle(thumbs[ThumbType.LEFT.getIndex()].pos + getPaddingLeft() + thumbWidth, getHeight() / 2f, circleRadius, edgePaint);
canvas.drawCircle(thumbs[ThumbType.RIGHT.getIndex()].pos - getPaddingRight(), getHeight() / 2f, circleRadius, edgePaint);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
Thumb mThumb;
Thumb mThumb2;
float coordinate = ev.getX();
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN -> {
// Remember where we started
currentThumb = getClosestThumb(coordinate);
if (currentThumb == -1)
return false;
mThumb = thumbs[currentThumb];
mThumb.lastTouchX = coordinate;
onSeekStart(this, currentThumb, mThumb.value);
return true;
}
case MotionEvent.ACTION_UP -> {
if (currentThumb == -1)
return false;
mThumb = thumbs[currentThumb];
onSeekStop(this, currentThumb, mThumb.value);
return true;
}
case MotionEvent.ACTION_MOVE -> {
mThumb = thumbs[currentThumb];
mThumb2 =
thumbs[currentThumb == ThumbType.LEFT.getIndex() ? ThumbType.RIGHT.getIndex() : ThumbType.LEFT.getIndex()];
// Calculate the distance moved
float dx = coordinate - mThumb.lastTouchX;
float newX = mThumb.pos + dx;
if (currentThumb == 0) {
if (newX + thumbWidth >= mThumb2.pos) {
mThumb.pos = mThumb2.pos - thumbWidth;
} else if (newX <= pixelRangeMin) {
mThumb.pos = pixelRangeMin;
} else {
// Check if thumb is not out of max width
checkPositionThumb(mThumb, mThumb2, dx, true);
// Move the object
mThumb.pos = mThumb.pos + dx;
// Remember this touch position for the next move event
mThumb.lastTouchX = coordinate;
}
} else if (newX <= mThumb2.pos + thumbWidth) {
mThumb.pos = mThumb2.pos + thumbWidth;
} else if (newX >= pixelRangeMax) {
mThumb.pos = pixelRangeMax;
} else {
// Check if thumb is not out of max width
checkPositionThumb(mThumb2, mThumb, dx, false);
// Move the object
mThumb.pos = mThumb.pos + dx;
// Remember this touch position for the next move event
mThumb.lastTouchX = coordinate;
}
setThumbPos(currentThumb, mThumb.pos);
// Invalidate to request a redraw
invalidate();
return true;
}
}
return false;
}
private void checkPositionThumb(Thumb thumbLeft, Thumb thumbRight, float dx, boolean isLeftMove) {
if (isLeftMove && dx < 0) {
if (thumbRight.pos - (thumbLeft.pos + dx) > maxWidth) {
thumbRight.pos = thumbLeft.pos + dx + maxWidth;
setThumbPos(ThumbType.RIGHT.getIndex(), thumbRight.pos);
}
} else if (!isLeftMove && dx > 0) {
if (thumbRight.pos + dx - thumbLeft.pos > maxWidth) {
thumbLeft.pos = thumbRight.pos + dx - maxWidth;
setThumbPos(ThumbType.LEFT.getIndex(), thumbLeft.pos);
}
}
}
private float pixelToScale(int index, float pixelValue) {
float scale = pixelValue * 100 / pixelRangeMax;
if (index == 0) {
float pxThumb = scale * thumbWidth / 100;
return scale + pxThumb * 100 / pixelRangeMax;
} else {
float pxThumb = (100 - scale) * thumbWidth / 100;
return scale - pxThumb * 100 / pixelRangeMax;
}
}
private float scaleToPixel(int index, float scaleValue) {
float px = scaleValue * pixelRangeMax / 100;
if (index == 0) {
float pxThumb = scaleValue * thumbWidth / 100;
return px - pxThumb;
} else {
float pxThumb = (100 - scaleValue) * thumbWidth / 100;
return px + pxThumb;
}
}
private void calculateThumbValue(int index) {
if (index < thumbs.length && thumbs.length != 0) {
Thumb th = thumbs[index];
th.value = pixelToScale(index, th.pos);
onSeek(this, index, th.value);
}
}
private void calculateThumbPos(int index) {
if (index < thumbs.length && thumbs.length != 0) {
Thumb th = thumbs[index];
th.pos = scaleToPixel(index, th.value);
}
}
private float getThumbValue(int index) {
return thumbs[index].value;
}
public void setThumbValue(int index, float value) {
thumbs[index].value = value;
calculateThumbPos(index);
// Tell the view we want a complete redraw
invalidate();
}
private void setThumbPos(int index, float pos) {
thumbs[index].pos = pos;
calculateThumbValue(index);
// Tell the view we want a complete redraw
invalidate();
}
private int getClosestThumb(float xPos) {
if (thumbs.length == 0)
return -1;
int closest = -1;
float minDistanceFound = Float.MAX_VALUE;
float x = xPos - thumbWidth;//+ paddingLeft
// Log.d("AppLog", "xPos:$xPos -> x: $x"); for (Thumb thumb : thumbs) { float thumbPos = thumb.index == ThumbType.LEFT.getIndex() ? thumb.pos : thumb.pos - thumbWidth; // Log.d("AppLog", "thumb ${thumb.index} pos: $thumbPos"); // Find thumb closest to x coordinate float xMin = thumbPos - thumbWidth * thumbTouchExtraMultiplier; float xMax = thumbPos + thumbWidth * thumbTouchExtraMultiplier; if (x >= xMin && x <= xMax) { float distance = Math.abs(thumbPos - x); if (distance < minDistanceFound) { closest = thumb.index; // Log.d("AppLog", "x: $x distance: $distance selectedThumb:$closest"); minDistanceFound = distance; } } } return closest; }
public void addOnRangeSeekBarListener(OnRangeSeekBarListener listener) {
listeners.add(listener);
}
private void onCreate(RangeSeekBarView rangeSeekBarView, int index, float value) {
for (OnRangeSeekBarListener item : listeners) {
item.onCreate(rangeSeekBarView, index, value);
}
}
private void onSeek(RangeSeekBarView rangeSeekBarView, int index, float value) {
for (OnRangeSeekBarListener item : listeners) {
item.onSeek(rangeSeekBarView, index, value);
}
}
private void onSeekStart(RangeSeekBarView rangeSeekBarView, int index, float value) {
for (OnRangeSeekBarListener item : listeners) {
item.onSeekStart(rangeSeekBarView, index, value);
}
}
private void onSeekStop(RangeSeekBarView rangeSeekBarView, int index, float value) {
for (OnRangeSeekBarListener item : listeners) {
item.onSeekStop(rangeSeekBarView, index, value);
}
}
public static class Thumb {
private final int index;
private float value;
private float pos;
private float lastTouchX;
public Thumb(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public float getValue() {
return value;
}
public void setValue(float value) {
this.value = value;
}
public float getPos() {
return pos;
}
public void setPos(float pos) {
this.pos = pos;
}
public float getLastTouchX() {
return lastTouchX;
}
public void setLastTouchX(float lastTouchX) {
this.lastTouchX = lastTouchX;
}
}
}
原文地址: https://www.cveoy.top/t/topic/eDUe 著作权归作者所有。请勿转载和采集!