💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
Android群英传读书笔记(第五章) 书中的示例代码:github 1.Android的坐标系是以左上角为顶点,向右为x轴正方向,向下是y轴正方向。在触控事件中通过getRawX()和getRawY()获取Android坐标系中的坐标。在View中通过getLocationOnScreen(intlocation[])获取。 2.视图坐标系描述的是子视图在父视图中的位置关系,原点为父视图的右上角,x、y轴方向与Android坐标系一致。触控事件中通过getX(),getY()获取。还可以通过getTop(),getLeft(),getBottom(),getRight()来获取到父视图的距离。 3.MotionEvent常用事件常量: MotionEvent.ACTION_DOWN//单点触摸按下动作 MotionEvent.ACTION_UP//单点触摸离开动作 MotionEvent.ACTION_MOVE//触摸点移动动作 MotionEvent.ACTION_CANCEL//触摸动作取消 MotionEvent.ACTION_OUTSIDE//触摸动作超出边界 MotionEvent.ACTION_POINTER_DOWN//多点触摸按下动作 MotionEvent.ACTION_POINTER_UP//多点离开动作 4.实现滑动的七种方法: layout()方法: private int lastX; private int lastY; private int offsetX; private int offsetY; @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getRawX(); int y = (int) event.getRawY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = x; lastY = y; break; case MotionEvent.ACTION_MOVE: offsetX = x - lastX; offsetY = y - lastY; layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY); lastX = x; lastY = y; break; } return true; } offsetLeftAndRight()和offsetTopAndBottom()方法: //替换上面的layout方法即可 offsetLeftAndRight(offsetX); offsetTopAndBottom(offsetY); LayoutParams方法: //替换上面的layout方法即可 ViewGroup.MarginLayoutParams layoutParams=(MarginLayoutParams) getLayoutParams(); layoutParams.leftMargin=getLeft()+offsetX; layoutParams.topMargin=getTop()+offsetY; setLayoutParams(layoutParams); scrollTo和scrollBy: //scrollTo和scrollBy移动的是view的内容而不是view本身 //如果在viewgroup中使用就是移动所有子view。 View view=(View) getParent(); //scrollTo和scrollBy参考的坐标系正好与视图坐标系相反,所以offset需为负 view.scrollBy(-offsetX, -offsetY); Scroller: 使用Scroller主要有三个步骤: 1.初始化Scroller对象,一般在view初始化的时候同时初始化scroller; 2.重写view的computeScroll方法,computeScroll方法是不会自动调用的,只能通过invalidate来间接调用,实现循环获取scrollX和scrollY的目的,当移动过程结束之后,Scroller.computeScrollOffset方法会返回false,从而中断循环; 3.调用Scroller.startScroll方法,将起始位置、偏移量以及移动时间(可选)作为参数传递给startScroll方法。 这个例子中,要实现的是view跟着手指滑动 松手后平滑移动到原位置。 先初始化Scroller mScroller=new Scroller(getContext()); 然后重写View的computeScroll()方法 @Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { ((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } } 最后在onTouchEvent的MotionEvent.ACTION_UP时开启移动 @Override public 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: int offsetX = x - lastX; int offsetY = y - lastY; ((View) getParent()).scrollBy(-offsetX, -offsetY); break; case MotionEvent.ACTION_UP: // 手指离开时,执行滑动过程 View viewGroup = ((View) getParent()); mScroller.startScroll( viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY(),1000); invalidate(); break; } return true; } Scroller的实现原理就是不断调用scrollTo或者scrollBy。 属性动画(以后章节会详细介绍) ViewDragHelper: ViewDragHelper基本可以实现各种不同滑动需求,但使用稍微复杂。 public class DragViewGroup extends FrameLayout { private ViewDragHelper mViewDragHelper; private View mMenuView, mMainView; private int mWidth; public DragViewGroup(Context context) { super(context); initView(); } public DragViewGroup(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } @Override protected void onFinishInflate() { super.onFinishInflate(); mMenuView = getChildAt(0); mMainView = getChildAt(1); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = mMenuView.getMeasuredWidth(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mViewDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { //将触摸事件传递给ViewDragHelper,此操作必不可少 mViewDragHelper.processTouchEvent(event); return true; } private void initView() { mViewDragHelper = ViewDragHelper.create(this, callback); } private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { // 何时开始检测触摸事件 @Override public boolean tryCaptureView(View child, int pointerId) { //如果当前触摸的child是mMainView时开始检测 return mMainView == child; } // 触摸到View后回调 @Override public void onViewCaptured(View capturedChild, int activePointerId) { super.onViewCaptured(capturedChild, activePointerId); } // 当拖拽状态改变,比如idle,dragging @Override public void onViewDragStateChanged(int state) { super.onViewDragStateChanged(state); } // 当位置改变的时候调用,常用与滑动时更改scale等 @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); } // 处理垂直滑动 @Override public int clampViewPositionVertical(View child, int top, int dy) { return 0; } // 处理水平滑动 @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return left; } // 拖动结束后调用 @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); //手指抬起后缓慢移动到指定位置 if (mMainView.getLeft() < 500) { //关闭菜单,相当于Scroller的startScroll方法 mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0); ViewCompat.postInvalidateOnAnimation(DragViewGroup.this); } else { //打开菜单 mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0); ViewCompat.postInvalidateOnAnimation(DragViewGroup.this); } } }; @Override public void computeScroll() { if (mViewDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } }