AndroidDeveloperLB / VideoTrimmer

Allows to trim videos on Android, including UI
MIT License
147 stars 25 forks source link

Please help me for RangeSeekBarView by Java language #15

Closed NightDeveloper-wq closed 3 years ago

NightDeveloper-wq commented 3 years ago

I wrote the java version of RangeSeekBar as I saw from you but my RangeSeekBarView can't drag. I couldn't find my mistake. I guess that getClosestThumb function. Please help me 🥇

public class RangeSeekBarView extends View {

    private List<Thumb> mThumbs;
    private HashSet<OnRangeSeekBarListener> mListeners;
    private float mMaxWidth;
    private int mThumbWidth;
    private int mViewWidth;
    private float mPixelRangeMin;
    private float mPixelRangeMax;
    private boolean mFirstRun;
    private final float mScaleRangeMax = 100f;
    private float thumbTouchExtraMultiplier;
    private int currentThumb;

    private final Paint shadowPaint = new Paint();
    private final Paint strokePaint = new Paint();
    private final Paint edgePaint = new Paint();

    public RangeSeekBarView(@NonNull Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RangeSeekBarView(@NonNull Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        Logger.i();
        mThumbs = new Vector<>();
        mThumbs.add(new Thumb(Thumb.ThumbType.LEFT));
        mThumbs.add(new Thumb(Thumb.ThumbType.RIGHT));

        thumbTouchExtraMultiplier = 1.0f;
        mListeners = new HashSet<>();
        currentThumb = Thumb.ThumbType.LEFT.ordinal();
        mThumbWidth = initThumbWidth();

        setFocusable(true);
        setFocusableInTouchMode(true);

        mFirstRun = true;

        shadowPaint.setAntiAlias(true);
        shadowPaint.setColor(0xB1000000);

        strokePaint.setAntiAlias(true);
        strokePaint.setStyle(Paint.Style.STROKE);
        strokePaint.setColor(0xffffffff);

        edgePaint.setAntiAlias(true);
        edgePaint.setColor(0xffffffff);
    }

    private int initThumbWidth() {
        return Math.max((int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 27f, MyApplication.getContext().getResources().getDisplayMetrics())), 1);
    }

    public void initMaxWidth() {
        Logger.i();
        mMaxWidth = mThumbs.get(Thumb.ThumbType.RIGHT.ordinal()).getPos() - mThumbs.get(Thumb.ThumbType.LEFT.ordinal()).getPos();

        onSeekStop(this, Thumb.ThumbType.LEFT.ordinal(), mThumbs.get(Thumb.ThumbType.LEFT.ordinal()).getVal());
        onSeekStop(this, Thumb.ThumbType.RIGHT.ordinal(), mThumbs.get(Thumb.ThumbType.RIGHT.ordinal()).getVal());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        mViewWidth = getMeasuredWidth();
        mPixelRangeMin = 0f;
        mPixelRangeMax = (float) (mViewWidth - mThumbWidth);

        if (mFirstRun) {
            for (Thumb thumb : mThumbs) {
                thumb.setVal(mScaleRangeMax * thumb.getIndex());
                thumb.setPos(mPixelRangeMax * thumb.getIndex());
            }
            // Fire listener callback
            onCreate(this, currentThumb, getThumbValue(currentThumb));
            mFirstRun = false;
        }
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        super.onDraw(canvas);

        if (mThumbs.isEmpty())
            return;

        // draw shadows outside of selected range
        for (Thumb th : mThumbs) {
            if (th.getIndex() == Thumb.ThumbType.LEFT.ordinal()) {
                final float x = th.getPos() + getPaddingLeft();
                if (x > mPixelRangeMin) {
                    canvas.drawRect((float) mThumbWidth, 0f, (x + mThumbWidth), (float) getHeight(), shadowPaint);
                }
            } else {
                final float x = th.getPos() - getPaddingRight();
                if (x < mPixelRangeMax) {
                    canvas.drawRect(x, 0f, (float) (mViewWidth - mThumbWidth), (float) getHeight(), shadowPaint);
                }
            }
        }

        //draw stroke around selected range
        canvas.drawRect((mThumbs.get(Thumb.ThumbType.LEFT.ordinal()).getPos() + getPaddingLeft() + mThumbWidth),
                0f,
                mThumbs.get(Thumb.ThumbType.RIGHT.ordinal()).getPos() - getPaddingRight(),
                (float) getHeight(), strokePaint);

        //draw edges
        float circleRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6f, MyApplication.getContext().getResources().getDisplayMetrics());
        canvas.drawCircle(mThumbs.get(Thumb.ThumbType.LEFT.ordinal()).getPos() + getPaddingLeft() + mThumbWidth,
                (float) getHeight() / 2f,
                circleRadius,
                edgePaint);

        canvas.drawCircle(mThumbs.get(Thumb.ThumbType.RIGHT.ordinal()).getPos() - getPaddingRight(),
                (float) getHeight() / 2f,
                circleRadius,
                edgePaint);
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent ev) {
        final Thumb mThumb;
        final Thumb mThumb2;
        final float coordinate = ev.getX();
        final int action = ev.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                // Remember where we started
                currentThumb = getClosestThumb(coordinate);

                if (currentThumb == -1) {
                    return false;
                }

                mThumb = mThumbs.get(currentThumb);
                mThumb.setLastTouchX(coordinate);
                onSeekStart(this, currentThumb, mThumb.getVal());
                return true;
            }
            case MotionEvent.ACTION_UP: {

                if (currentThumb == -1) {
                    return false;
                }

                mThumb = mThumbs.get(currentThumb);
                onSeekStop(this, currentThumb, mThumb.getVal());
                return true;
            }

            case MotionEvent.ACTION_MOVE: {
                mThumb = mThumbs.get(currentThumb);
                mThumb2 = mThumbs.get(currentThumb == Thumb.ThumbType.LEFT.ordinal() ? Thumb.ThumbType.RIGHT.ordinal() : Thumb.ThumbType.LEFT.ordinal());
                // Calculate the distance moved
                final float dx = coordinate - mThumb.getLastTouchX();
                final float newX = mThumb.getPos() + dx;
                if (currentThumb == 0) {

                    if ((newX + mThumbWidth) >= mThumb2.getPos()) {
                        mThumb.setPos(mThumb2.getPos() - mThumbWidth);
                    } else if (newX <= mPixelRangeMin) {
                        mThumb.setPos(mPixelRangeMin);
                    } else {
                        //Check if thumb is not out of max width
                        checkPositionThumb(mThumb, mThumb2, dx, true);
                        // Move the object
                        mThumb.setPos(mThumb.getPos() + dx);

                        // Remember this touch position for the next move event
                        mThumb.setLastTouchX(coordinate);
                    }

                } else {
                    if (newX <= mThumb2.getPos() + mThumbWidth) {
                        mThumb.setPos(mThumb2.getPos() + mThumbWidth);
                    } else if (newX >= mPixelRangeMax) {
                        mThumb.setPos(mPixelRangeMax);
                    } else {
                        //Check if thumb is not out of max width
                        checkPositionThumb(mThumb2, mThumb, dx, false);
                        // Move the object
                        mThumb.setPos(mThumb.getPos() + dx);
                        // Remember this touch position for the next move event
                        mThumb.setLastTouchX(coordinate);
                    }
                }

                setThumbPos(currentThumb, mThumb.getPos());

                // Invalidate to request a redraw
                invalidate();
                return true;
            }
        }
        return false;
    }

    private void checkPositionThumb(@NonNull Thumb mThumbLeft, @NonNull Thumb mThumbRight, float dx, boolean isLeftMove) {
        if (isLeftMove && dx < 0) {
            if ((mThumbRight.getPos() - (mThumbLeft.getPos() + dx)) > mMaxWidth) {
                mThumbRight.setPos(mThumbLeft.getPos() + dx + mMaxWidth);
                setThumbPos(Thumb.ThumbType.RIGHT.ordinal(), mThumbRight.getPos());
            }
        } else if (!isLeftMove && dx > 0) {
            if (((mThumbRight.getPos() + dx) - mThumbLeft.getPos()) > mMaxWidth) {
                mThumbLeft.setPos(mThumbRight.getPos() + dx - mMaxWidth);
                setThumbPos(Thumb.ThumbType.LEFT.ordinal(), mThumbLeft.getPos());
            }
        }
    }

    private float pixelToScale(int index, float pixelValue) {
        float scale = (pixelValue * 100) / mPixelRangeMax;
        if (index == Thumb.ThumbType.LEFT.ordinal()) {
            float pxThumb = (scale * mThumbWidth) / 100;
            return scale + (pxThumb * 100) / mPixelRangeMax;
        } else {
            float pxThumb = ((100 - scale) * mThumbWidth) / 100;
            return scale - (pxThumb * 100) / mPixelRangeMax;
        }
    }

    private float scaleToPixel(int index, float scaleValue) {
        float px = (scaleValue * mPixelRangeMax) / 100;
        if (index == 0) {
            float pxThumb = (scaleValue * mThumbWidth) / 100;
            return px - pxThumb;
        } else {
            float pxThumb = ((100 - scaleValue) * mThumbWidth) / 100;
            return px + pxThumb;
        }
    }

    private void calculateThumbValue(int index) {
        if (index < mThumbs.size() && !mThumbs.isEmpty()) {
            Thumb th = mThumbs.get(index);
            th.setVal(pixelToScale(index, th.getPos()));
            onSeek(this, index, th.getVal());
        }
    }

    private void calculateThumbPos(int index) {
        if (index < mThumbs.size() && !mThumbs.isEmpty()) {
            Thumb th = mThumbs.get(index);
            th.setPos(scaleToPixel(index, th.getVal()));
        }
    }

    private float getThumbValue(int index) {
        return mThumbs.get(index).getVal();
    }

    public void setThumbValue(int index, float value) {
        mThumbs.get(index).setVal(value);
        calculateThumbPos(index);
        // Tell the view we want a complete redraw
        invalidate();
    }

    private void setThumbPos(int index, float pos) {
        mThumbs.get(index).setPos(pos);
        calculateThumbValue(index);
        // Tell the view we want a complete redraw
        invalidate();
    }

    private int getClosestThumb(float coordinate) {
        int closest = -1;
        if (mThumbs.isEmpty())
            return -1;

        float minDistanceFound = Float.MAX_VALUE;
        float x = coordinate - mThumbWidth;//+ getPaddingLeft()

        for (Thumb thumb : mThumbs) {
            float thumbPos;
            if (thumb.getIndex() == Thumb.ThumbType.LEFT.ordinal()) {
                thumbPos = thumb.getPos();
            } else {
                thumbPos = thumb.getPos() - mThumbWidth;
            }

            float xMin = thumbPos - mThumbWidth * thumbTouchExtraMultiplier;
            float xMax = thumbPos + mThumbWidth * thumbTouchExtraMultiplier;

            if (x <= xMin && x >= xMax) {
                float distance = Math.abs(thumbPos - x);
                if (distance < minDistanceFound) {
                    closest = thumb.getIndex();
                    minDistanceFound = distance;
                }
            }
        }
        return closest;
    }

    public int getThumbWidth() {
        return mThumbWidth;
    }

    public void addOnRangeSeekBarListener(OnRangeSeekBarListener listener) {
        mListeners.add(listener);
    }

    private void onCreate(RangeSeekBarView rangeSeekBarView, int index, float value) {
        for (OnRangeSeekBarListener item : mListeners) {
            item.onCreate(rangeSeekBarView, index, value);
        }
    }

    private void onSeek(RangeSeekBarView rangeSeekBarView, int index, float value) {
        for (OnRangeSeekBarListener item : mListeners) {
            item.onSeek(rangeSeekBarView, index, value);
        }
    }

    private void onSeekStart(RangeSeekBarView rangeSeekBarView, int index, float value) {
        for (OnRangeSeekBarListener item : mListeners) {
            item.onSeekStart(rangeSeekBarView, index, value);
        }
    }

    private void onSeekStop(RangeSeekBarView rangeSeekBarView, int index, float value) {
        for (OnRangeSeekBarListener item : mListeners) {
            item.onSeekStop(rangeSeekBarView, index, value);
        }
    }
}
AndroidDeveloperLB commented 3 years ago

No need. There is Kotlin version. An Android developer should know both languages, especially the newly default one.

AndroidDeveloperLB commented 3 years ago

Besides, as I wrote, it's based on this, which is in Java: https://github.com/titansgroup/k4l-video-trimmer