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

编程入门 行业动态 更新时间:2024-10-13 16:21:22

<a href=https://www.elefans.com/category/jswz/34/1771438.html style=自定义View——左右裁剪长按移动控件"/>

自定义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();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected 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);//绘制当前Pathfor (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;}@Overridepublic 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);}@Overridepublic 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;@Overridepublic 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);}@Overridepublic 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;@Overridepublic 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);}@Overrideprotected 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>() {@Overridepublic 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() {@Overridepublic 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);}@Overridepublic 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;}@Overridepublic 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);}}@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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();}
}

更多推荐

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

本文发布于:2024-02-24 15:52:30,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1695833.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:自定义   控件   View

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!