在自定义View,以及属性动画中常用到以下属性: scrollX/scrollY,translationX/translationY,x/y,LayoutParams
1.scrollX/scrollY 对于这两个属性,View中提供了很多公有方法对其进行设置:
1 2 3 4 1 、setScrollX(int value)/setScrollY(int value); 2 、scrollTo(int x, int y);3 、scrollBy(int x, int y);
通过源代码我们发现以上方法最终调用的都是scrollTo(int x,int y)
方法:
1 2 3 4 5 6 7 8 9 10 11 public void setScrollX (int value) { scrollTo(value, mScrollY); } public void setScrollY (int value) { scrollTo(mScrollX, value); } public void scrollBy (int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }
其中需要注意的是scrollBy与scrollTo的区别在于:scrollBy设置的是相对值,scrollTo设置的是绝对值 。
** ScrollTo方法滑动的是View里面的内容 ** 在这里我们创建一个类ScrollView继承自TextView并重载里面的onTouchEvent方法,为了便于观察在这里我们只处理x方向的滑动,同时将模拟器的布局边界打开。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class ScrollView extends TextView { ... private float lastX; @Override public boolean onTouchEvent (MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = event.getX(); break ; case MotionEvent.ACTION_MOVE: float currX = event.getX(); scrollBy((int ) (lastX - currX), 0 ); lastX = currX; break ; } return true ; } ... }
在布局文件中使用ScrollView类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:layout_width ="match_parent" android:gravity ="center" android:layout_height ="match_parent" > <cn.hufeifei.scrolltest.view.ScrollView android:layout_width ="160dp" android:layout_height ="160dp" android:background ="#fbb" android:gravity ="center" android:text ="scroll" android:textColor ="#00f" android:textSize ="20sp" /> </LinearLayout >
下面是运行效果图:
使用这个方法我们可以模仿ViewPager自定义一个更加简洁的页面滑动的控件。
2.translationX/translationY 与translationX/translationY类似的属性有很多,这些属性都存在View的RenderNode成员中。
1 2 3 4 5 6 7 8 final RenderNode mRenderNode;
根据文档注释我们可以知道RenderNode其实是一个专门存放View的属性的容器,这些属性都是与View显示相关的属性,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 boolean setAlpha (float alpha) float getAlpha () boolean setElevation (float lift) float getElevation () boolean setTranslationX (float translationX) float getTranslationX () boolean setTranslationY (float translationY) float getTranslationY () boolean setTranslationZ (float translationZ) float getTranslationZ () boolean setRotation (float rotation) float getRotation () boolean setRotationX (float rotationX) float getRotationX () boolean setRotationY (float rotationY) float getRotationY () boolean setScaleX (float scaleX) float getScaleX () boolean setScaleY (float scaleY) float getScaleY () boolean setPivotX (float pivotX) float getPivotX () boolean setPivotY (float pivotY) float getPivotY () boolean setLeft (int left) boolean setTop (int top) boolean setRight (int right) boolean setBottom (int bottom)
在View中与这些属性相关的get/set方法大都直接或间接的调用了RenderNode的相关get/set方法。
在这里为了实现滑动效果,同时为了便于观察,我们只修改translationX属性 同样的我们定义一个类TranslationView继承自TextView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class TranslationView extends TextView { ... private float lastX; @Override public boolean onTouchEvent (MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = event.getX(); break ; case MotionEvent.ACTION_MOVE: float currX = event.getX(); float distanceX = currX - lastX; setTranslationX(getTranslationX() + distanceX); lastX = currX; break ; } return true ; } }
在布局中使用TranslationView类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:layout_width ="match_parent" android:layout_height ="match_parent" android:gravity ="center" > <cn.hufeifei.scrolltest.view.TranslationView android:layout_width ="160dp" android:layout_height ="160dp" android:background ="#aaf" android:gravity ="center" android:text ="translation" android:textColor ="#f00" android:textSize ="20sp" /> </LinearLayout >
我们可以看到平移属性只是将View的绘制进行了平移,View的定位并没有发生改变
在View中还有几个属性与方法与translationX/translationY有着密不可分的关系
1 2 3 4 5 6 7 8 9 10 11 12 public float getX () { return mLeft + getTranslationX(); } public void setX (float x) { setTranslationX(x - mLeft); } public float getY () { return mTop + getTranslationY(); } public float getY () { return mTop + getTranslationY(); }
在前面的我们说到left,top,right,bottom几个属性都是android系统用来进行布局定位的,开发者一般无法进行修改。这四个属性在view中对应着:mLeft,mTop,mRight,mBottom字段。
这几个属性之间有以下关系: 1、 x = left + translationX 2、 y = top + translationY
将上面的效果图进行了一些处理,得到以下关系图:
需要注意的是这里的left/top属性与x/y属性都是相对于父容器得到的。 LayoutParams的margin属性 看到这个属性,很容易就联想到前端CSS中的盒子模型概念。安卓中margin,padding的概念与前端CSS类似。
同样的我们以marginLeft作为操作对象,来创建一个TextView的子类LayoutView。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class LayoutView extends TextView { ... private float lastX; @Override public boolean onTouchEvent (MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = event.getX(); break ; case MotionEvent.ACTION_MOVE: float currX = event.getX(); LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) getLayoutParams(); params.leftMargin += currX - lastX; requestLayout(); lastX = currX; break ; } return true ; } }
并将其使用在布局文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" android:layout_width ="match_parent" android:layout_height ="match_parent" android:gravity ="center" > <cn.hufeifei.scrolltest.view.LayoutView android:layout_width ="160dp" android:layout_height ="160dp" android:background ="#cfc" android:gravity ="center" android:text ="layout" android:textColor ="#00f" android:textSize ="20sp" /> </LinearLayout >
运行得到效果图如下:
可以看到我点击鼠标往做移动,marginLeft减小成负数,使得控件往也左移动。在前端CSS中我们为了实现特殊的定位要求也经常用到类似的方法。
三种滑动方式的对比 1、通过修改scrollX/scrollY属性达到滑动效果:它可以方便地实现滑动效果而且不影响内部元素的单击事件。但是它只能滑动View的内容,并不能滑动View本身。 2、View本身定位没有发生改变,只是绘制的位置发生了改变 3、从布局上改变了View本身的定位。
刚开始写博客,不正确的地方请多多指正
本作品采用 知识共享署名 4.0 国际许可协议 进行许可。
转载时请注明原文链接 :https://blog.hufeifei.cn/2016/12/Android/scroll-translation-LayoutParams/