Android View移动的3种方式总结
前言
在android开发中,view一直是android开发人员的一块心病,一方面想要进阶,一方面又害怕进阶,可以说android的view是进阶路上的最大绊脚石,因为它涉及的东西太多了,比如本次我们此次要写的view移动,另外还包括view的触摸事件的传递,创建自定义view,这些都是极其重要且不得不面对的难题。但是无论如何,现在不克服的困难将来就会被困难克服。
在此之前,我们还是先了解android坐标系的定义规则以及view的一些位置参数。
android坐标系
view的位置及大小是由四个参数决定,即left、top、right、bottom,并且这四个参数都是相对于其父view的。
int width = right-left; int height = bottom-top;
在activity中布局完成后,我们可以通过view一些方法获取这些参数信息:
//left,top,right,bottom值的获取 int left = getleft(); int top = gettop(); int right = getright(); int bottom = getbottom();
另外android 3.0以后加入x,y,translationx,translationy等参数。(x,y)表示为view在viewgroup中左上角的x,y的值,translationx,translationy在用于平移一个view。默认是都为0,在调用了view的settranslationx()/settranslationy()
之后发生改变。
//x,y,translationx,translationy参数的获取 int x = getx(); int y = gety(); int translationx = gettranslationx(); int translationy = gettranslationy();
ps:调用view的settranslationx()
和settranslationy()
方法虽然可以使得view平移指定距离,但是这一过程是瞬间完成的。为了使view的移动使得更为平滑,因此可以使用view的属性动画来指定translationx和translationy。
objectanimator valueanimator = objectanimator.offloat(textview, "translationx", 200); valueanimator.setduration(2000); valueanimator.start();
另外,如果给view设置settranslationx()
和settranslationy()
后,如果设置的值没有发生变化,那么其只会移动一次,即首次指定的移动距离。查看源码后我们发现原因:原来在设置值之后其会将设置进去的值和当前的translationx,translationy进行对比,不一致时才进行移动。
了解了view的一些基本参数之后,我们看关于view的三种移动方式。
一、使用android系统提供的scrollto()/scrollby()方法实现view的移动。
不管是scrollto()
还是scrollby()
其移动的本质都是view/viewgroup中的内容。并且其移动的过程是瞬间完成的,因此,为了实现更好的移动效果,他需要与scroller类结合使用。另外,它不同于上面的translation,移动的是view本身,这一点需要好好理解一下。
scrollto()
和scrollby()
都是view中的方法, 不是scroller中的方法 ,但是控制view的平滑移动与scroller类密不可分。
scrollto() :
指是的移动的绝对位置,如果位置没有变化,多次调用则不会起作用。
scrollto移动过程示意图
scrollby() :
其本质依然是调用的scrollto()
,指的的移动当前位置的相对距离(每次都是先将当前的位置和设置的距离相加之和调用scrollto(),这样如果你多次调用,你就会发现其每次都会移动一段距离,这是和scrollto()的本质区别)
scrollby移动过程示意图
ps:关于上面两张图,其实一直以来,我自己都没完全搞明白什么相对绝对,所以两张手图可能会让人更容易理解。还有就是scrollto()
和scrollby()
移动方向问题,上面我们已经画过android的坐标系,x轴左→右为正,y轴从上→下为正。但是这并不适用于scrollto和scrollby,scrollto和scrollby刚好相反,即x轴左→右为负,y轴从上→下为负,简直是有点坑爹啊。
scroller类分析:而为什么使用scroller类中的方法可以对view/viewgroup的内容进行移动呢?下面我们试着分析一下。
首先
我们创建一个scroller类的对象mscroller。
然后
要使view在规定的时间中移动到指定的位置,我们会调用startscroll()
方法,startscroll()
是scroller
类中的方法,另外scroller
类中还有一个filing()
方法也是很常用的,它主要是处理平滑的移动,一般营造滑动之后的惯性效果,使得view的移动更逼真。下面我们看startscroll()
的源码:
//其接收四个/五个参数。如果duration不设置,则为默认。这四个参数都不难理解,这里不再做解释。 public void startscroll(int startx, int starty, int dx, int dy, int duration) { ... }
而一般我们调用这个方法后都要去调view的 invalidate()
,这个方法可以触发view的draw()
方法。而draw()中
调用了 computescroll()
,源码中我们发现computescroll()是
个空方法,这也是为什么我们需要重写 computescroll()
方法的原因。因为正在的移动操作就是在computescroll()
中进行的。
@override public void computescroll() { if (mscroller.computescrolloffset()) { scrollto(mscroller.getcurrx(), mscroller.getcurry()); //必须调用view的postinvalidate()/invalidate(),如果不加会导致view的移动只会第一帧。 postinvalidate(); } super.computescroll(); }
上面我们看到scroller类中还有一个computescrolloffset()
方法,它又是干啥的呢?它的主要作用就是判断mcurrx,和mcurry是否有改变,有则返回true,无则返回false。通过这个方法的判断可以指点是否需要持续的调用scrollto()
去移动view。这里再给出一个示例,使用scrollto()
让view跟着手指移动:
public class cuview extends linearlayout { private float mstartx; private float mstarty; private scroller mscroller; /** * 第一次滑动是否完成 */ private boolean isfirstfinish; public cuview(context context) { super(context); init(context); } public cuview(context context, attributeset attrs) { super(context, attrs); init(context); } private void init(context context) { mscroller = new scroller(context); } public cuview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(context); } @targetapi(build.version_codes.lollipop) public cuview(context context, attributeset attrs, int defstyleattr, int defstyleres) { super(context, attrs, defstyleattr, defstyleres); init(context); } /** * 让view跟着你的手指走吧 * @param event * @return */ @override public boolean ontouchevent(motionevent event) { int action = event.getaction(); switch (action) { case motionevent.action_down: /** * 第一次移动完成后,我们不需要再去拿开始的位置了,否则造成view重新移动的最起始的位置。 */ if (!isfirstfinish) { mstartx = event.getrawx(); mstarty = event.getrawy(); } break; case motionevent.action_move: scrollto((int) (mstartx - event.getrawx()), (int) (mstarty - event.getrawy())); break; case motionevent.action_up: //第一次移动完成 isfirstfinish = true; break; } return true; } /** * 测试startscroll */ public void startscroll() { /** * 注意scroller移动方向, */ mscroller.startscroll(20, 20, -500, -500, 5000); invalidate(); } @override public void computescroll() { if (mscroller.computescrolloffset()) { scrollto(mscroller.getcurrx(), mscroller.getcurry()); invalidate(); } super.computescroll(); } }
二、使用动画实现view的移动。
这里包括view的tween animation/frame animation,以及3.0之后加入的property animation。其移动的是view的一个映像,view本身的位置及大小并没有发生任何改变。
三、设置view的layoutparams来移动view
linearlayout.layoutparams layoutparams = (linearlayout.layoutparams) textview.getlayoutparams(); layoutparams.leftmargin = 50; textview.requestlayout();
总结
以上就是总结android view移动的3种方式的全部内容了,希望本文的内容对大家开发android的时候能有所帮助,如果有疑问大家可以留言交流。
上一篇: Effective C# 使用成员初始化器而不是赋值语句
下一篇: php接口技术实例详解