View小知识

xiaoxiao2021-02-28  59

**内容导视:** 1. 先了解基本的api 2. 3种方式实现全屏随手滑动的自定义view

基本的API 针对于View的子类View的 view.getX( ),view.getLeft( ),view.getTranslationX( ),e.getX( ),e.getRawX( ) view.getY( ),view.getTop( ),view.getTranslationY(( ),e.getY( ),e.getRawY( )


布局:注意这里view设置了margin的

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:background="#34495e" android:onClick="click" android:text="移动view的位置" android:textColor="#fff"/> <com.docwei.democeshi.MyTextView android:id="@+id/view" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginLeft="60dp" android:layout_marginTop="50dp" android:background="#1abc9c" android:text="我是内容" android:textColor="#fff" android:textStyle="bold"/> </RelativeLayout>

最初显示view的位置 点击移动View的位置之后:

mView.setTranslationX(getResources().getDimensionPixelSize(R.dimen.move_x)); mView.setTranslationY(getResources().getDimensionPixelSize(R.dimen.move_y)) 得出的结论是: view.getX( )=view.getLeft( )+view.getTranslationX( ) view.getY( )=view.getTop( )+view.getTranslationY( )

可以把view.getLeft( )与view.getTop( )看成一个final的常量(最初布局完成之后就不会再改变的) 想要获取移动的控件左上角坐标的位置是不能通过getLeft()或者getTop(),因为大部分情况都不是我们想要的结果。 也不能轻易的把view.getX( )或者view.getY( )来作为view左上角的坐标,要考虑margin的情况。



e.getRawX( )可以看做是按下的点在在屏幕的X坐标 e.getRawY( )可以看做是按下的点在屏幕的Y坐标,注意(包括了导航栏和actionBar的高度) e.getX( )是按下的点相对于控件的X的位置 e.getY( )是按下的点相对于控件的Y的位置


接下来:做一个随手滑动的view(类似于launcer上图标可以拖动的效果)来验证这些值 到底有几种方式实现随手滑动的自定义view ? 实现: 方式一:通过按下的点的移动变化来计算控件(左上角坐标)的变化,这里view的移动使用view属性平移动画,传入控件左上角的坐标的上一个值和下一个值,启动动画达到效果。那关键就是获取控件左上角的坐标,从图上就可以看出。 方式二:通过按下的点的移动变化来计算控件(左上角坐标)的变化,获取view.setX( value)来做,能用setTranslationX()方法实现那一定可以通过这个setX()来实现,只是传入值的问题。 方式三:比较简单,直接获取leftMargin和topMargin确定view的位置,然后直接setLayoutParams(params)实现。

方式一:具体代码: public class MyTextView extends TextView { private static final String TAG = "MyTextView"; private int mScreenWidth; private int mScreenHeight; private final int mTouchSlop; private int mOffsetY; public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); mScreenWidth=context.getResources().getDisplayMetrics().widthPixels; mScreenHeight=context.getResources().getDisplayMetrics().heightPixels; mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } //***************************方式一start*************************************** private int leftMargin; private int topMargin; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if(oldw!=w){ CoordinatorLayout.MarginLayoutParams params= (CoordinatorLayout.MarginLayoutParams) getLayoutParams(); leftMargin=params.leftMargin; topMargin=params.topMargin; } } int downPointX; int downPointY; int moveLastPointX; int moveLastPointY; int downX; int downY; int moveLastX; int moveLastY; boolean flag=false; public void setOffsetY(int offsetY) { //mOffsetY就是导航栏和actionbar的高度之和 mOffsetY = offsetY; } @Override public boolean onTouchEvent(MotionEvent e) { switch (e.getAction()){ case MotionEvent.ACTION_DOWN: //根据按下点的位置获取view的左上角的坐标 downPointX = (int) (e.getRawX()-e.getX()); downPointY = (int) (e.getRawY()-e.getY()); downX= (int) e.getRawX(); downY= (int) e.getRawY(); flag=true; break; case MotionEvent.ACTION_MOVE: if(flag){ moveLastPointX = downPointX; moveLastPointY = downPointY; moveLastX=downX; moveLastY=downY; flag=false; } int moveX = (int) e.getRawX(); int moveY = (int) e.getRawY(); int realdx=moveX-moveLastX; int realdy=moveY-moveLastY; if(Math.abs(realdx)<mTouchSlop&&Math.abs(realdy)<mTouchSlop){ return true; } //获取移动后的坐标 int movePointX=moveLastPointX +realdx; int movePointY=moveLastPointY +realdy; //边界值限定------start--------- if(movePointX<0){ movePointX=0; } if(movePointX>mScreenWidth-getMeasuredWidth()){ movePointX=mScreenWidth-getMeasuredWidth(); } if(movePointY<0){ movePointY=0; } if(movePointY>mScreenHeight-getMeasuredHeight()){ movePointY=mScreenHeight-getMeasuredHeight(); } //边界值限定------end------------ //这里使用属性动画,其实就是左上角坐标的变化,, //最后两个参数,一个是之前的坐标,再一个就是平移之后的坐标,这个Y坐标要是相对于父布局的坐标,而不是屏幕的坐标 //Y要减去的是状态栏和导航栏的高度, //使用属性动画还要考虑leftMargain和topMargin ObjectAnimator animX=ObjectAnimator.ofFloat(this,"TranslationX", moveLastPointX-leftMargin, movePointX-leftMargin); ObjectAnimator animY=ObjectAnimator.ofFloat(this,"TranslationY", moveLastPointY-mOffsetY-topMargin, movePointY-mOffsetY-topMargin); animX.setDuration(10); animY.setDuration(10); animX.start(); animY.start(); moveLastPointX = movePointX; moveLastPointY = movePointY; moveLastX=moveX; moveLastY=moveY; break; case MotionEvent.ACTION_UP: break; } return true; } }

获取actionBar和到导航栏的高度,可以在activity的oncreate方法里面获取

private void initData() { mView = (MyTextView) findViewById(R.id.view); mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect rectgle= new Rect(); Window window= getWindow(); window.getDecorView().getWindowVisibleDisplayFrame(rectgle); int StatusBarHeight= rectgle.top; int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop(); int TitleBarHeight= contentViewTop - StatusBarHeight; mView.setOffsetY(contentViewTop); mView.getViewTreeObserver().removeOnGlobalLayoutListener(this); } }); } 方法二: public boolean onTouchEvent(MotionEvent e) { switch (e.getAction()){ case MotionEvent.ACTION_DOWN: //根据按下点的位置获取view的左上角的坐标 downPointX = (int) (e.getRawX()-e.getX()); downPointY = (int) (e.getRawY()-e.getY()); downX= (int) e.getRawX(); downY= (int) e.getRawY(); flag=true; break; case MotionEvent.ACTION_MOVE: if(flag){ moveLastPointX = downPointX; moveLastPointY = downPointY; moveLastX=downX; moveLastY=downY; flag=false; } int moveX = (int) e.getRawX(); int moveY = (int) e.getRawY(); int realdx=moveX-moveLastX; int realdy=moveY-moveLastY; if(Math.abs(realdx)<mTouchSlop&&Math.abs(realdy)<mTouchSlop){ return true; } //获取移动后的坐标 int movePointX=moveLastPointX +realdx; int movePointY=moveLastPointY +realdy; //边界值限定------start--------- if(movePointX<0){ movePointX=0; } if(movePointX>mScreenWidth-getMeasuredWidth()){ movePointX=mScreenWidth-getMeasuredWidth(); } if(movePointY<0){ movePointY=0; } if(movePointY>mScreenHeight-getMeasuredHeight()){ movePointY=mScreenHeight-getMeasuredHeight(); } //边界值限定------end------------ setX(movePointX); setY(movePointY-mOffsetY); moveLastPointX = movePointX; moveLastPointY = movePointY; moveLastX=moveX; moveLastY=moveY; break; case MotionEvent.ACTION_UP: break; } return true; } 方式三: public class MyTextView extends TextView { private static final String TAG = "MyTextView"; private int mScreenWidth; private int mScreenHeight; private final int mTouchSlop; public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); mScreenWidth=context.getResources().getDisplayMetrics().widthPixels; mScreenHeight=context.getResources().getDisplayMetrics().heightPixels; mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } int downPointX; int downPointY; int moveLastPointX; int moveLastPointY; private boolean flag=false; @Override public boolean onTouchEvent(MotionEvent event) { CoordinatorLayout.MarginLayoutParams layoutParams = (CoordinatorLayout.MarginLayoutParams) getLayoutParams(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { //根据按下点的位置 downPointX = (int) event.getRawX(); downPointY = (int) event.getRawY(); flag=true; return true; } case MotionEvent.ACTION_MOVE: { if(flag){ moveLastPointX = downPointX; moveLastPointY = downPointY; flag=false; } //获取变化的差值 int moveX = (int) event.getRawX(); int moveY = (int) event.getRawY(); int realdx=moveX-moveLastPointX; int realdy=moveY-moveLastPointY; //根据变化的差值来设置左上方向的margin确定控件的位置 int left = layoutParams.leftMargin +realdx; int top = layoutParams.topMargin + realdy; //边界值限定------start--------- if(left<0){ left=0; } if(left>mScreenWidth-getMeasuredWidth()){ left=mScreenWidth-getMeasuredWidth(); } if(top<0){ top=0; } if(top>mScreenHeight-getMeasuredHeight()){ //有必要的话还需要考虑虚拟键的高度 top=mScreenHeight-getMeasuredHeight(); } //边界值限定------end------------ layoutParams.leftMargin = left; layoutParams.topMargin = top; setLayoutParams(layoutParams); //记住最后的位置,把这赋给上一个点 moveLastPointX=moveX; moveLastPointY=moveY; break; } case MotionEvent.ACTION_UP: { break; } } return true; } }

代码其实都是很简单,只是用来让大家验证 demo源码地址: http://download.csdn.net/download/doc__wei/9895669

转载请注明原文地址: https://www.6miu.com/read-81496.html

最新回复(0)