欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android继承ViewGroup实现Scroll滑动效果的方法示例

程序员文章站 2023-12-10 19:51:34
本文实例讲述了android继承viewgroup实现scroll滑动效果的方法。分享给大家供大家参考,具体如下: extends viewgroup需要重写onmeas...

本文实例讲述了android继承viewgroup实现scroll滑动效果的方法。分享给大家供大家参考,具体如下:

extends viewgroup需要重写onmeasure和onlayout方法

onmeasure方法是去测量viewgroup需要的大小以及包含的子view需要的大小。

执行完上面的方法后,再执行onlayout方法去设置子view的摆放位置。

实现scroll滑动效果需要去检测滑动速率,即要知道每个单位时间滑动了多少像素值,根据这个像素值去判断scroll滑动到下一页还是上一页。

android为我们提供了velocitytracker这个类检测速率

使用mvelocitytracker = velocitytracker.obtain();来初始化

使用mvelocitytracker.addmovement(event);将touch事件添加进去检测。注意每个touch事件都要添加进去

使用mvelocitytracker.computecurrentvelocity(1000);计算每个单位时间内滑动了多少像素,这里传入的是1000ms即1s。

然后使用float pxsec = mvelocitytracker.getxvelocity();获取到x轴滑动的像素值,必须在执行了上面方法只会再调用。

最后需要mvelocitytracker.recycle();mvelocitytracker = null;回收掉这个对象。

完整代码是:

public class myscrolllayout extends viewgroup{
 private int curscreen;
 private int defaultscreen = 0;
 private scroller mscroller;
 private float mlastmotionx = 0;
 private velocitytracker mvelocitytracker;

 public myscrolllayout(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  init(context);
 }
 public myscrolllayout(context context, attributeset attrs) {
  super(context, attrs);
  init(context);
 }
 public myscrolllayout(context context) {
  super(context);
  init(context);
 }
 private void init(context context){
  curscreen = defaultscreen;
  mscroller = new scroller(context);
 }
 @override
 public void computescroll() {
  if(mscroller.computescrolloffset()){
   scrollto(mscroller.getcurrx(), mscroller.getcurry());
   postinvalidate();
  }
 }
 @override
 public boolean ontouchevent(motionevent event) {
  // todo auto-generated method stub
  int action = event.getaction();
  float x = event.getx();
  switch (action) {
  case motionevent.action_down:
   if(mvelocitytracker==null){
    mvelocitytracker = velocitytracker.obtain();
    mvelocitytracker.addmovement(event);
   }
   if(!mscroller.isfinished()){
    mscroller.abortanimation();
   }
   mlastmotionx = event.getx();
   break;
  case motionevent.action_move:
   float delt = mlastmotionx-x;
   if(iscanmove((int)delt)){
   if(mvelocitytracker!=null){
    mvelocitytracker.addmovement(event);
   }
   mlastmotionx = x;
   scrollby((int)delt, 0);
   }
   break;
  case motionevent.action_up:
   if(mvelocitytracker!=null){
    mvelocitytracker.addmovement(event);
    mvelocitytracker.computecurrentvelocity(1000);
    float pxsec = mvelocitytracker.getxvelocity();
    if(pxsec>600 && curscreen >0){
     snaptoscreen(curscreen-1);
    }else if(pxsec<-600 && curscreen<getchildcount()-1){
     snaptoscreen(curscreen+1);
    }else{
     //主要是用来获取该滑动到哪个界面,最终调用的是invalid调用draw方法然后draw调用computescroll方法,然后使用scroller对象
     snaptodestination();
    }
    mvelocitytracker.recycle();
    mvelocitytracker = null;
   }
   break;
  default:
   break;
  }
  return true;
 }
 private void snaptoscreen(int screen){
  int whichscreen = math.max(0, math.min(screen, getchildcount()-1));
  if(getscrollx()!=(whichscreen*getwidth())){
   final int delat = whichscreen*getwidth() - getscrollx();
   mscroller.startscroll(getscrollx(), 0, delat, 0, math.abs(delat)*2);
   curscreen = whichscreen;
   invalidate();
  }
 }
 private void snaptodestination(){
  int screen = (getscrollx()+getwidth()/2)/getwidth();
  snaptoscreen(screen);
 }
 private boolean iscanmove(int delat){
  /*if(getscrollx()<0 && delat<0){
   return false;
  }*/
  if(getscrollx()>=(getchildcount()-1)*getwidth() && delat>0){
   return false;
  }
  return true;
 }
 @override
 protected void onlayout(boolean changed, int l, int t, int r, int b) {
  if(changed){
  int totalheight = 0;
  int totalwidth = 0;
  int childcount = getchildcount();
  for(int i=0; i<childcount; i++){
   view childview = getchildat(i);
   int childwidth = childview.getmeasuredwidth();
   int childheight = childview.getmeasuredheight();
   childview.layout(totalwidth, t, totalwidth+childwidth, b);
   totalheight += childheight;
   totalwidth += childwidth;
  }
  }
 }
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
  // todo auto-generated method stub
  measurechildren(widthmeasurespec, heightmeasurespec);
  super.onmeasure(widthmeasurespec, heightmeasurespec);
 }
}

很多人会以为viewgroup的滑动是scroller的功劳,其实不然,scroller在这里扮演的角色我认为更像是一个用来计算x和y轴单位时间移动像素的工具类而已,仅此而已没有特别的能力。

真正在这里实现scroll滑动效果的是viewgroup里的scrollto和scrollby方法,scrollto是滑动到,scrollby是滑动了。

scroller.startscroll(getscrollx(), 0, delat, 0, math.abs(delat)*2);

scroller这个类的startscroll方法传入了五个参数,分别对应,x轴起滑的偏移像素,y轴起滑的偏移像素,x轴滑动像素,y轴滑动像素,滑动过程需要的时间。

看源码如果不传时间参数的方法有个默认的时间250ms。

scroller.startscroll之后需要调用invalidate方法,然后调用viewgroup的draw方法,然后调用computescroll方法,在computescroll方法里面调用scroller.computescrolloffset()方法去判断有没有计算完,没计算完返回true,然后scrollto方法,再postinvalidate();方法重新执行computescroll方法。

更多关于android相关内容感兴趣的读者可查看本站专题:《android开发入门与进阶教程》、《android开发动画技巧汇总》、《android多媒体操作技巧汇总(音频,视频,录音等)》、《android基本组件用法总结》、《android视图view技巧总结》、《android布局layout技巧总结》及《android控件用法总结

希望本文所述对大家android程序设计有所帮助。