Android 跟随手指移动的圆

来源:互联网 发布:模糊c均值聚类算法 编辑:程序博客网 时间:2024/04/29 22:49

通过onTouchEvent实现一个简单的跟随触摸点移动的圆

public class CircleFollowView extends View {private static final String Tag = "CircleFollowView";private float currentX = 50;private float currentY = 50;private int radius = 50;// 控件宽度private int mWidth;// 控件高度private int mHeight;private int lastX;private int lastY;public CircleFollowView(Context context) {super(context);}public CircleFollowView(Context context, AttributeSet attrs) {super(context, attrs);}public CircleFollowView(Context context, AttributeSet attrs,int defStyleAttr) {super(context, attrs, defStyleAttr);}private void initView() {// 取最小的长度的一半作为半径// layout中View要设定绝对大小,例如具体dp或者match_patent,否则点击屏幕其他地方也可能移动圆this.radius = (mWidth / 2 < mHeight / 2) ? mWidth / 2 : mHeight / 2;this.currentX = mWidth / 2;this.currentY = mHeight / 2;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);if (widthMode == MeasureSpec.EXACTLY) {mWidth = widthSize;} else if (widthMode == MeasureSpec.AT_MOST) {throw new IllegalArgumentException("width must be EXACTLY,you should set like android:width=\"200dp\"");}if (heightMode == MeasureSpec.EXACTLY) {mHeight = heightSize;} else if (widthMeasureSpec == MeasureSpec.AT_MOST) {throw new IllegalArgumentException("height must be EXACTLY,you should set like android:height=\"200dp\"");}setMeasuredDimension(mWidth, mHeight);}@SuppressLint("DrawAllocation")@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);initView();Paint p = new Paint();p.setColor(Color.RED);canvas.drawCircle(currentX, currentY, radius, p);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// 触摸点到屏幕左上角的距离int rawX = (int) event.getRawX();int rawY = (int) event.getRawY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:lastX = rawX;lastY = rawY;break;case MotionEvent.ACTION_MOVE:int offsetX = rawX - lastX;int offsetY = rawY - lastY;offsetLeftAndRight(offsetX);offsetTopAndBottom(offsetY);lastX = rawX;lastY = rawY;break;case MotionEvent.ACTION_UP:lastX = rawX;lastY = rawY;break;}return true;}}

上面一种方式是通过修改View距离屏幕的位置实现滑动,下面使用Scroller(其他内容相同,只展示onTouchEvent部分):

int offsetX;int offsetY;@Overridepublic boolean onTouchEvent(MotionEvent event) {int x = (int) event.getX();int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:lastX = (int) event.getX();lastY = (int) event.getY();break;case MotionEvent.ACTION_MOVE:offsetX = x - lastX;offsetY = y - lastY; ((View) getParent()).scrollBy(-offsetX, -offsetY); invalidate();break;default:break;}return true;}

scroll的位移从左到右为负值,从右到左是正值,从上到下是负值,从下到上是正值,所以使用scrollBy时参数取负。

((View) getParent()).scrollBy(-offsetX, -offsetY);如果替换为

View viewGroup = ((View) getParent());
mScroller.startScroll(viewGroup.getScrollX(),  viewGroup.getScrollY(), -offsetX, -offsetY,1000);//1s完成滑动

需要配合

        public void computeScroll() {super.computeScroll();if (mScroller.computeScrollOffset()) {((View) getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());// 通过重绘来不断调用computeScrollinvalidate();}}

通过invalidate()->onDraw()->computeScroll()一部分一部分重绘实现滑动,但是不能实时,可以实现一种延迟的滑动效果。

scrollTo/scrollBy这种方式能比较方便的实现滑动效果并且不影响点击时间,但是他只能滑动View的内部,所以上面代码中滑动使用的是getParent(),实际运用时,滑动的部分最好单独写在一个ViewGroup中,否则父组件内的所有内容会一起滑动。

第三种修改LayoutParams,向左移动,就增加marginLeft:

public boolean onTouchEvent(MotionEvent event) {// 触摸点到屏幕左上角的距离int rawX = (int) event.getRawX();int rawY = (int) event.getRawY();VelocityTracker velocityTracker = VelocityTracker.obtain();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:lastX = rawX;lastY = rawY;break;case MotionEvent.ACTION_MOVE:int offsetX = rawX - lastX;int offsetY = rawY - lastY;MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams();layoutParams.leftMargin += offsetX;layoutParams.topMargin += offsetY;requestLayout();//或者setLayoutParams(layoutParams);lastX = rawX;lastY = rawY;break;case MotionEvent.ACTION_UP:lastX = rawX;lastY = rawY;break;}return true;}

最后,如果滑动的效果不是实时的,也可以采用动画的方式,动画比较适合复杂的效果和没有交互的View。


0 0
原创粉丝点击