自定义View——左右裁剪长按移动控件

预览效果

在这里插入图片描述

目录

  • AudioSpectrum.java
  • MusicSlideLView.java
  • MusicSlideRView.java
  • MusicLayout.java

代码

  • AudioSpectrum

public class AudioSpectrum extends View {

    private Paint paint, bgPaint;

    private int lineWidth = getContext().getResources().getDimensionPixelSize(R.dimen.music_space);
    private int lineColor = Color.parseColor("#999999");
    private int lineCheckColoe = Color.parseColor("#FF0000");

    private int radius = DensityUtil.dp2PxInt(getContext(), 3);

    private boolean isCheckState = false;

    private List<Float> values = new ArrayList<>();

    private int parentWidth;

    public AudioSpectrum(Context context) {
        super(context);

        initView();
    }

    public AudioSpectrum(Context context, AttributeSet attrs) {
        super(context, attrs);

        initView();
    }

    public AudioSpectrum(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initView();
    }

    private void initView() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(lineWidth);
        paint.setStrokeJoin(Paint.Join.ROUND);

        bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bgPaint.setStyle(Paint.Style.FILL);
        bgPaint.setColor(Color.parseColor("#666666"));
    }

    /**
     * 返回振幅数
     *
     * @return
     */
    public int getValueCount() {
        if (null != values)
            return values.size();

        return 0;
    }

    /**
     * 设置振幅值
     *
     * @param values
     */
    public void setValues(List<Float> values) {
        this.values = values;
        requestLayout();
    }

    public void setCheckState(boolean checkState) {
        isCheckState = checkState;
        invalidate();
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRoundRect(getScrollX(), 0, getScrollX() + getWidth(), getHeight(), radius, radius, bgPaint);
        if (isCheckState) {
            paint.setColor(lineCheckColoe);
        } else {
            paint.setColor(lineColor);
        }

        //记录起点位置
        float bsHeight = getHeight() * 1f / 2 - 2;
        PathPoint lastPath = new PathPoint(0, bsHeight);

        //循环,分段绘制
        List<PathPoint> src = new ArrayList<>();
        for (int i = 0; i < values.size(); i++) {
            //保存
            float pointX = i * lineWidth;
            float pointY = bsHeight - bsHeight * values.get(i);
            PathPoint pathPoint = new PathPoint(pointX, pointY);
            src.add(pathPoint);
            //每100条绘制一次,或者到最后了绘制
            if (i != 0 && (i % 100 == 0) || (i == values.size() - 1)) {
                //移动到上一次位置
                Path path = new Path();
                path.moveTo(lastPath.pointX, lastPath.pointY);
                //绘制当前Path
                for (int j = 0; j < src.size(); j++) {
                    PathPoint pp = src.get(j);
                    path.lineTo(pp.pointX, pp.pointY);
                }
                //反向
                for (int j = (src.size() - 1); j >= 0; j--) {
                    PathPoint pp = src.get(j);
                    path.lineTo(pp.pointX, getHeight() - pp.pointY);
                }
                //闭合
                path.lineTo(lastPath.pointX, getHeight() - lastPath.pointY);
                path.close();
                //绘制
                canvas.drawPath(path, paint);
                //记录结束的位置
                lastPath = pathPoint;
                //清空
                src.clear();
            }
        }
    }

    public void setUnitLength(int unitLength) {
        this.lineWidth = unitLength;
    }

    public void setParentWidth(int width) {
        this.parentWidth = width;
    }

    public static class PathPoint {
        public float pointX;
        public float pointY;

        public PathPoint(float pointX, float pointY) {
            this.pointX = pointX;
            this.pointY = pointY;
        }

        @Override
        public String toString() {
            return "******pointX:" + pointX + "******pointY:" + pointY;
        }
    }
}
  • MusicSlideLView

public class MusicSlideLView extends View {
    private Paint paint;

    private int pl = getContext().getResources().getDimensionPixelSize(R.dimen.time_line_ml);

    private OnMusicSlideLListener onMusicSlideLListener;

    public MusicSlideLView(Context context) {
        super(context);
        initView();
    }

    public MusicSlideLView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public MusicSlideLView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);

        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(pl, ViewGroup.LayoutParams.MATCH_PARENT);
        setLayoutParams(lp);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        Bitmap slideL = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_slide_l);
        float ratio = slideL.getWidth() * 1f / slideL.getHeight();
        int dstw = (int) (ratio * getHeight());
        Rect src = new Rect(0, 0, slideL.getWidth(), slideL.getHeight());
        Rect dst;
        if (pl < dstw) {
            dst = new Rect(0, 0, pl, getHeight());
        } else {
            dst = new Rect(pl - dstw, 0, pl, getHeight());
        }
        canvas.drawBitmap(slideL, src, dst, paint);
    }

    private float lastX;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = event.getRawX();
                // 让父类不要拦截该view的事件
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = event.getRawX();
                int dx = (int) (moveX - lastX);

                //防止误滑
                if (Math.abs(dx) > 5) {
                    if (null != onMusicSlideLListener) {
                        onMusicSlideLListener.onSlideL(dx);
                    }
                    lastX = moveX;
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

    public void setOnMusicSlideLListener(OnMusicSlideLListener onMusicSlideLListener) {
        this.onMusicSlideLListener = onMusicSlideLListener;
    }

    public interface OnMusicSlideLListener {
        void onSlideL(int dx);
    }
}
  • MusicSlideRView

public class MusicSlideRView extends View {
    private Paint paint;

    private int pr = getContext().getResources().getDimensionPixelSize(R.dimen.time_line_mr);

    private OnMusicSlideRListener onMusicSlideRListener;

    public MusicSlideRView(Context context) {
        super(context);
        initView();
    }

    public MusicSlideRView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public MusicSlideRView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);

        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(pr, ViewGroup.LayoutParams.MATCH_PARENT);
        setLayoutParams(lp);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        Bitmap slideR = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_slide_r);
        float ratio = slideR.getWidth() * 1f / slideR.getHeight();
        int dstw = (int) (ratio * getHeight());
        Rect src = new Rect(0, 0, slideR.getWidth(), slideR.getHeight());
        Rect dst;
        if (pr < dstw) {
            dst = new Rect(getWidth() - pr, 0, getWidth(), getHeight());
        } else {
            dst = new Rect(0, 0, dstw, getHeight());
        }
        canvas.drawBitmap(slideR, src, dst, paint);
    }

    private float lastX;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = event.getRawX();
                // 让父类不要拦截该view的事件
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = event.getRawX();
                int dx = (int) (moveX - lastX);

                //防止误滑
                if (Math.abs(dx) > 5) {
                    if (null != onMusicSlideRListener) {
                        onMusicSlideRListener.onSlideR(dx);
                    }
                    lastX = moveX;
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

    public void setOnMusicSlideRListener(OnMusicSlideRListener onMusicSlideRListener) {
        this.onMusicSlideRListener = onMusicSlideRListener;
    }

    public interface OnMusicSlideRListener {
        void onSlideR(int dx);
    }
}
  • MusicLayout

public class MusicLayout extends FrameLayout implements MusicSlideRView.OnMusicSlideRListener, MusicSlideLView.OnMusicSlideLListener {

    //左右边距,拉伸图宽度
    private int pl = getContext().getResources().getDimensionPixelSize(R.dimen.time_line_ml);
    private int pr = getContext().getResources().getDimensionPixelSize(R.dimen.time_line_mr);

    private int radius = DensityUtil.dp2PxInt(getContext(), 3);

    public int textColor = Color.parseColor("#999999");
    public int textSize = DensityUtil.sp2px(getContext(), 12);

    private Paint bgPaint;
    private MusicSlideLView ivSL;
    private MusicSlideRView ivSR;

    private MusicTouchListener musicTouchListener;

    private List<View> audioSpectrums = new ArrayList<>();

    private TextPaint textPaint;

    public MusicLayout(@NonNull Context context) {
        super(context);

        initView();
    }

    public MusicLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        initView();
    }

    public MusicLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initView();
    }

    private void initView() {
        //禁止多点触控
        setMotionEventSplittingEnabled(false);

        bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bgPaint.setStyle(Paint.Style.FILL);
        bgPaint.setColor(Color.parseColor("#333333"));

        textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setTextSize(textSize);
        textPaint.setColor(textColor);
        textPaint.setTextAlign(Paint.Align.LEFT);

        //左右
        ivSL = new MusicSlideLView(getContext());
        ivSL.setOnMusicSlideLListener(this);
        ivSR = new MusicSlideRView(getContext());
        ivSR.setOnMusicSlideRListener(this);
    }

    public void setWidth(int mWidth) {
        ViewGroup.LayoutParams lp = getLayoutParams();
        lp.width = mWidth + pl + pr;
        setLayoutParams(lp);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.drawRoundRect(pl, 0, getMeasuredWidth() - pr, getMeasuredHeight(), radius, radius, bgPaint);

        if (audioSpectrums.size() == 0) {
            Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
            float distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
            float baseline = getHeight() * 1.0f / 2 + distance;
            canvas.drawText("点击添加音乐", pl + 20, baseline, textPaint);
        }
        super.dispatchDraw(canvas);
    }

    public void addChildView(int length, int ml, List<Float> list) {
        int width = getWidth();
        AudioSpectrum audioSpectrum = new AudioSpectrum(getContext());
        LayoutParams lp = new LayoutParams(length, ViewGroup.LayoutParams.MATCH_PARENT);
        lp.leftMargin = pl + ml;
        audioSpectrum.setLayoutParams(lp);
        audioSpectrum.setParentWidth(width - pl - pr);
        audioSpectrum.setValues(list);
        audioSpectrum.setTag(ml);
        addView(audioSpectrum);
        audioSpectrums.add(audioSpectrum);

        hideStroke();

        Collections.sort(audioSpectrums, new Comparator<View>() {
            @Override
            public int compare(View view, View t1) {
                FrameLayout.LayoutParams lp1 = (LayoutParams) view.getLayoutParams();
                FrameLayout.LayoutParams lp2 = (LayoutParams) t1.getLayoutParams();
                return lp1.leftMargin - lp2.leftMargin;
            }
        });
    }

    //当前点击的View和索引
    private View currentView;
    private int currentIndex = -1;

    //是否可移动
    private boolean canTouch = false;

    private float lastX;
    //是否长按
    private boolean isClick = false;
    //是否长按
    private boolean isLong = false;
    //是否可以长按
    private boolean canLong = false;

    //滑动累加
    private int scrollLength = 0;

    //事件类型
    private int touchType = 0;

    private Handler handler = new Handler();
    private Runnable longPressRun = new Runnable() {
        @Override
        public void run() {
            if (canLong && canTouch) {
                vibrator();
                isLong = true;
                isClick = false;
                touchType = 3;
            }
        }
    };

    private Vibrator vibrator;

    /**
     * 振动
     */
    private void vibrator() {
        if (null == vibrator)
            vibrator = (Vibrator) getContext().getSystemService(getContext().VIBRATOR_SERVICE);
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (vibrator.hasVibrator()) {
                vibrator.vibrate(VibrationEffect.createOneShot(100, 200));
            }
        } else {
            if (vibrator.hasVibrator()) {
                vibrator.vibrate(100);
            }
        }
    }


    /**
     * 判断是否在child中
     *
     * @param view
     * @param raxX
     * @param raxY
     * @return
     */
    private boolean isConstains(View view, float raxX, float raxY) {
        int[] location = new int[2];
        // 获取控件在屏幕中的位置,返回的数组分别为控件左顶点的 x、y 的值
        view.getLocationOnScreen(location);
        RectF rectF = new RectF(location[0], location[1], location[0] + view.getWidth(), location[1] + view.getHeight());
        return rectF.contains(raxX, raxY);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = event.getRawX();
                float raxY = event.getRawY();

                for (int i = 0; i < getChildCount(); i++) {
                    View child = getChildAt(i);
                    if (child instanceof AudioSpectrum && isConstains(child, lastX, raxY)) {
                        this.currentView = child;
                        this.currentIndex = audioSpectrums.indexOf(currentView);
                        break;
                    }
                }
                Log.e("currentView", "*******" + currentView);
                if (null != currentView) {
                    isLong = false;
                    canLong = true;
                    isClick = true;

                    touchType = 0;
                    handler.postDelayed(longPressRun, ViewConfiguration.getLongPressTimeout());

                    if (null != musicTouchListener) {
                        musicTouchListener.onTouchStart();
                    }
                } else {
                    isClick = true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (!canTouch || null == currentView || -1 == currentIndex) {
                    return false;
                }

                float moveX = event.getRawX();
                int dx = (int) (moveX - lastX);

                //防止误滑
                if (Math.abs(dx) > 10) {
                    handler.removeCallbacks(longPressRun);
                    canLong = false;
                    isClick = false;
                }
                if (3 == touchType) {
                    //通过设置边距移动
                    FrameLayout.LayoutParams lp = (LayoutParams) currentView.getLayoutParams();
                    if (lp == null) {
                        lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
                    }
                    //计算可移动距离
                    int moveLeft = (lp.leftMargin - pl) + dx;
                    if (moveLeft < 0) {
                        moveLeft = 0;
                    } else {
                        //判断可移动距离 TODO
//                        long inPoint = MusicTractHelper.getInstance().isOverlap(currentIndex, mapTimelinePosFromScrollerX(moveLeft));
//                        moveLeft = mapTimelinePosFromTs(inPoint);
                    }

                    lp.leftMargin = pl + moveLeft;
                    currentView.setLayoutParams(lp);
                    refreshSlideLR(currentView);
                    if (null != musicTouchListener) {
                        musicTouchListener.move(currentIndex, mapTimelinePosFromScrollerX(moveLeft));
                    }
                }
                lastX = moveX;
                break;
            case MotionEvent.ACTION_UP:
                handler.removeCallbacks(longPressRun);
                if (isClick) {
                    if (-1 != currentIndex && null != currentView) {
                        showSlideLR(currentIndex, currentView);
                    }
                    if (null != musicTouchListener) {
                        musicTouchListener.onTap(currentIndex);
                    }
                }
                touchType = 0;

                isClick = false;
                isLong = false;
                canLong = false;

                if (null != musicTouchListener) {
                    musicTouchListener.onTouchEnd();
                }

                break;
        }
        return true;
    }

    @Override
    public void onSlideL(int dx) {
        if (!canTouch || null == currentView || -1 == currentIndex) {
            return;
        }

        Log.e("onSlideL", "************dx:" + dx);

        //防止误滑
        if (Math.abs(dx) > 10) {
            handler.removeCallbacks(longPressRun);
            canLong = false;
            isClick = false;
        }

        //重置布局
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) currentView.getLayoutParams();
        if (lp == null) {
            lp = new FrameLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        }

        //新的宽度
        Log.e("onSlideL", "************getWidth:" + currentView.getWidth());
        int newWidth = currentView.getWidth() - dx;
        Log.e("onSlideL", "************newWidth:" + newWidth);
        int timeLength = getWidth() - pl - pr - (lp.leftMargin - pl);
        Log.e("timeLength", "************timeLength:" + timeLength);

        //计算当前显示的宽度对应的时长
        long showLength = mapTimelinePosFromScrollerX(newWidth);
        //吸附
//        showLength = MusicTractHelper.getInstance().getLeftToPointerShowLength(showLength);

        //判断显示时长不小于1秒
        if (showLength < 1000000) {
            showLength = 1000000;
        }
        Log.e("showLength", "************showLength:" + showLength);
        //判断是否重叠 TODO
//        showLength = MusicTractHelper.getInstance().isInPointOverlap(currentIndex, showLength);
//        Log.e("showLength", "************showLength:" + showLength);

        //重新计算dx;
        dx = currentView.getWidth() - mapTimelinePosFromTs(showLength);
        Log.e("dx", "************dx:" + dx);
        //滚动
        scrollLength += dx;
        currentView.scrollTo(scrollLength, 0);

        lp.width = mapTimelinePosFromTs(showLength);
        lp.leftMargin = lp.leftMargin + dx;
        currentView.setLayoutParams(lp);
        //重新加载右拉伸图片
        showSlideL(currentView);
        //回调
        if (null != musicTouchListener) {
            musicTouchListener.slideLeft(currentIndex, showLength);
        }
    }

    @Override
    public void onSlideR(int dx) {
        if (!canTouch || null == currentView || -1 == currentIndex) {
            return;
        }

        Log.e("onSlideR", "************dx:" + dx);

        //防止误滑
        if (Math.abs(dx) > 10) {
            handler.removeCallbacks(longPressRun);
            canLong = false;
            isClick = false;
        }

        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) currentView.getLayoutParams();
        if (lp == null) {
            lp = new FrameLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        }

        //新的宽度
        int newWidth = currentView.getWidth() + dx;
        int timeLength = getWidth() - pl - pr - (lp.leftMargin - pl);
        //判断宽度不小于0,不大于父控件的宽度
        int minLength = mapTimelinePosFromTs(1000000);
        if (newWidth < minLength) {
            newWidth = minLength;
        } else if (newWidth > timeLength) {
            newWidth = timeLength;
        }
        //计算当前显示的宽度对应的时长
        long showLength = mapTimelinePosFromScrollerX(newWidth);
        //判断是否重叠 TODO
//        showLength = MusicTractHelper.getInstance().isOutPointOverlap(currentIndex, showLength);
        //重置布局

        lp.width = mapTimelinePosFromTs(showLength);
        currentView.setLayoutParams(lp);
        //重新加载右拉伸图片
        showSlideR(currentView);
        //回调
        if (null != musicTouchListener) {
            musicTouchListener.slideRight(currentIndex, showLength);
        }
    }

    /**
     * 显示左右拉伸图标
     *
     * @param currentIndex
     * @param currentView
     */
    private void showSlideLR(int currentIndex, View currentView) {
        //设置当前索引 TODO
//        MusicTractHelper.getInstance().setCurrentMusicIndex(currentIndex);
        //切换音频状态
        changeSpectrumState(true, currentIndex);

        //刷新位置
        refreshSlideLR(currentView);
        if (!canTouch) {
            this.canTouch = true;
            //重新添加
            addView(ivSL);
            addView(ivSR);
        }
    }

    /**
     * 显示左右拉伸图标
     *
     * @param currentView
     */
    private void refreshSlideLR(View currentView) {
        showSlideL(currentView);
        showSlideR(currentView);
    }

    public void hideStroke() {
        //切换音频状态
        changeSpectrumState(false, currentIndex);
        //取消当前索引 TODO
//        MusicTractHelper.getInstance().setCurrentMusicIndex(-1);
        //清除当前View和索引
        currentView = null;
        currentIndex = -1;
        //取消移动
        this.canTouch = false;
        //取消左右图标
        removeView(ivSL);
        removeView(ivSR);
    }

    /**
     * 切换音频图状态
     *
     * @param isFoucs
     * @param currentIndex
     */
    private void changeSpectrumState(boolean isFoucs, int currentIndex) {
        for (int i = 0; i < audioSpectrums.size(); i++) {
            View childView = audioSpectrums.get(i);
            if (childView instanceof AudioSpectrum) {
                ((AudioSpectrum) childView).setCheckState(isFoucs && i == currentIndex);
            }
        }
    }

    /**
     * 显示左拉伸图
     *
     * @param currentView
     */
    private void showSlideL(final View currentView) {
        currentView.post(new Runnable() {
            @Override
            public void run() {
                LayoutParams leftLp = (LayoutParams) ivSL.getLayoutParams();
                if (null == leftLp) {
                    leftLp = new LayoutParams(pl, ViewGroup.LayoutParams.MATCH_PARENT);
                }
                int left = currentView.getLeft() - pl;
                if (left != leftLp.leftMargin) {
                    leftLp.leftMargin = currentView.getLeft() - pl;
                    ivSL.setLayoutParams(leftLp);
                }
            }
        });
    }

    /**
     * 显示右拉伸图
     *
     * @param currentView
     */
    private void showSlideR(final View currentView) {
        currentView.post(new Runnable() {
            @Override
            public void run() {
                LayoutParams rightLp = (LayoutParams) ivSR.getLayoutParams();
                if (null == rightLp) {
                    rightLp = new LayoutParams(pr, ViewGroup.LayoutParams.MATCH_PARENT);
                }
                int left = currentView.getRight();
                if (left != rightLp.leftMargin) {
                    rightLp.leftMargin = left;
                    ivSR.setLayoutParams(rightLp);
                }
            }
        });
    }

    private double getPixelPerMicrosecond() {
        long durationPerScreen = 1000000 * 14;
        int width = DensityUtil.getScreenWidth(getContext());
        double pixelMicrosecond = width / (double) durationPerScreen;
        return pixelMicrosecond;
    }

    public long mapTimelinePosFromScrollerX(int scrollX) {
        return (long) (scrollX / getPixelPerMicrosecond());
    }

    public int mapTimelinePosFromTs(long t) {
        return (int) (t * getPixelPerMicrosecond());
    }

    public void setMusicTouchListener(MusicTouchListener musicTouchListener) {
        this.musicTouchListener = musicTouchListener;
    }

    public void removeChildView(int index) {
        View childView = audioSpectrums.get(index);
        removeView(childView);
        audioSpectrums.remove(index);
        hideStroke();
    }

    public void removeAllChildView() {
        audioSpectrums.clear();
        removeAllViews();
    }

    public interface MusicTouchListener {
        void onTouchStart();

        void slideLeft(int index, long showLength);

        void move(int index, long inPoint);

        void slideRight(int index, long showLength);

        void onTap(int currentIndex);

        void onTouchEnd();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
自定义控件是Android开发中常见的任务之一。下面是一步一步教你如何自定义控件的简要指南: 第一步:创建一个新的Java类作为你的自定义控件。 首先,创建一个新的Java类,可以命名为你想要的控件名称。这个类应该继承自Android框架中的现有控件,例如View、TextView等。例如,如果你想要创建一个自定义按钮,可以创建一个名为CustomButton的类,并让它继承自Button类。 第二步:实现构造函数和属性。 在你的自定义控件类中,你可以实现构造函数和属性,以便对控件进行初始化和设置。你可以定义自己的属性,例如颜色、大小等,以及相应的getter和setter方法。 第三步:重写绘制方法。 要自定义控件的外观,你需要重写它的绘制方法。最常用的方法是重写`onDraw()`方法,在其中使用Canvas绘制你想要的形状、文本等。 第四步:处理用户交互。 如果你的自定义控件需要与用户进行交互,你可以重写相应的触摸事件(例如`onTouchEvent()`)或点击事件(例如`setOnClickListener()`)来处理用户操作。 第五步:在布局文件中使用自定义控件。 完成以上步骤后,你可以在布局文件中使用你的自定义控件了。只需在布局文件中添加一个与你的控件类名相对应的XML标签,并设置相应的属性。 这只是一个简要的指南,帮助你开始自定义控件的过程。在实际开发中,你可能需要更多的步骤和细节来完成你的自定义控件。你可以参考Android官方文档或其他教程来获取更多信息和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜小徐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值