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

Android自定义ViewFlipper实现滚动效果

程序员文章站 2022-04-29 10:29:01
本文实例为大家分享了自定义view实现了类似百度手机助手,首页评论滚动效果。 看效果: gif做的不好,其效果就是:几个viewitem不停的向上滚动,新加入ite...

本文实例为大家分享了自定义view实现了类似百度手机助手,首页评论滚动效果。

看效果:

Android自定义ViewFlipper实现滚动效果

gif做的不好,其效果就是:几个viewitem不停的向上滚动,新加入item有个淡入的效果。

说下实现思路:自定义view继承至linearlayout,控制item数量及其动画效果,实现item复用,传入数据即可,使用方便。

代码:

/**
 * jiantao.yang
 *
 * @description 仿百度手机助手,评论滚动效果
 * @time 2015/1/16 17:37
 */
public class viewflipper extends linearlayout {
 
 private final int max_show_item_size = 5;
 
 private iadapter miadapter;
 
 private int mcount;
 
 //最后一个item动画
 private animation mlastoneanimation;
 
 //其它item动画
 private animation mcommonanimation;
 
 //数据下标
 private int mcurrentindex;
 
 /**
  * 这里动画时间是1600毫秒,所以间隔得大于动画时间
  */
 private static final int default_interval = 2000;
 
 private int mflipinterval = default_interval;
 
 private boolean mautostart = false;
 
 private boolean mrunning = false;
 private boolean mstarted = false;
 private boolean mvisible = false;
 private boolean muserpresent = true;
 
 public viewflipper(context context) {
  super(context);
  init(context);
 }
 
 public viewflipper(context context, attributeset attrs) {
  super(context, attrs);
  init(context);
 }
 
 public viewflipper(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  init(context);
 }
 
 private final broadcastreceiver mreceiver = new broadcastreceiver() {
  @override
  public void onreceive(context context, intent intent) {
   final string action = intent.getaction();
   if (intent.action_screen_off.equals(action)) {
    muserpresent = false;
    updaterunning();
   } else if (intent.action_user_present.equals(action)) {
    muserpresent = true;
    updaterunning(false);
   }
  }
 };
 
 @override
 protected void onattachedtowindow() {
  super.onattachedtowindow();
 
  // listen for broadcasts related to user-presence
  final intentfilter filter = new intentfilter();
  filter.addaction(intent.action_screen_off);
  filter.addaction(intent.action_user_present);
 
  // ok, this is gross but needed. this class is supported by the
  // remote views machanism and as a part of that the remote views
  // can be inflated by a context for another user without the app
  // having interact users permission - just for loading resources.
  // for exmaple, when adding widgets from a user profile to the
  // home screen. therefore, we register the receiver as the current
  // user not the one the context is for.
  getcontext().registerreceiver(mreceiver, filter);
 
  if (mautostart) {
   // automatically start when requested
   startflipping();
  }
 }
 
 @override
 protected void ondetachedfromwindow() {
  super.ondetachedfromwindow();
  mvisible = false;
 
  getcontext().unregisterreceiver(mreceiver);
  updaterunning();
 }
 
 @override
 protected void onwindowvisibilitychanged(int visibility) {
  super.onwindowvisibilitychanged(visibility);
  mvisible = visibility == visible;
  updaterunning(mvisible);
//  updaterunning(false);
 }
 
 private void init(context context) {
  this.setorientation(linearlayout.vertical);
 }
 
 public void setiadapter(iadapter iadapter) {
  this.miadapter = iadapter;
  initshowitems();
 }
 
 public void startflipping() {
  mstarted = true;
  updaterunning();
 }
 
 public void stopflipping() {
  mstarted = false;
  updaterunning();
 }
 
 private void updaterunning() {
  updaterunning(true);
 }
 
 /**
  * returns true if the child views are flipping.
  */
 public boolean isflipping() {
  return mstarted;
 }
 
 /**
  * set if this view automatically calls {@link #startflipping()} when it
  * becomes attached to a window.
  */
 public void setautostart(boolean autostart) {
  mautostart = autostart;
 }
 
 /**
  * returns true if this view automatically calls {@link #startflipping()}
  * when it becomes attached to a window.
  */
 public boolean isautostart() {
  return mautostart;
 }
 
 @override
 public void oninitializeaccessibilityevent(accessibilityevent event) {
  super.oninitializeaccessibilityevent(event);
  event.setclassname(viewflipper.class.getname());
 }
 
 @override
 public void oninitializeaccessibilitynodeinfo(accessibilitynodeinfo info) {
  super.oninitializeaccessibilitynodeinfo(info);
  info.setclassname(viewflipper.class.getname());
 }
 
 /**
  * 初始化childviews
  */
 private void initshowitems() {
  if (miadapter != null) {
   mcount = miadapter.getcount();
   for (int i = 0; i < mcount; i++) {
    if (i == max_show_item_size) {
     break;
    }
    view convertview = getchildat(i);
    view item = miadapter.getitemview(convertview, i);
    addview(item, i);
   }
  }
 }
 
 /**
  * internal method to start or stop dispatching flip {@link android.os.message} based
  * on {@link #mrunning} and {@link #mvisible} state.
  *
  * @param flipnow determines whether or not to execute the animation now, in
  *    addition to queuing future flips. if omitted, defaults to
  *    true.
  */
 private void updaterunning(boolean flipnow) {
  boolean running = mvisible && mstarted && muserpresent;
  system.out.println(" updaterunning running:" + running + " mvisible " + mvisible + " userpresent " + muserpresent);
  if (running != mrunning) {
   if (running && (mcount > max_show_item_size)) {
    showitems(mcurrentindex++, flipnow);
    message msg = mhandler.obtainmessage(flip_msg);
    mhandler.sendmessagedelayed(msg, mflipinterval);
   } else {
    mhandler.removemessages(flip_msg);
   }
   mrunning = running;
  }
 }
 
 
 private void showitems(final int position, boolean animate) {
  if (animate && (mlastoneanimation == null || mcommonanimation == null)) {
   mlastoneanimation = animationutils.loadanimation(getcontext(), r.anim.lastone_anim);
   mcommonanimation = animationutils.loadanimation(getcontext(), r.anim.common_anim);
  }
  int childcount = getchildcount();
  for (int i = 0; i < childcount; i++) {
   view child = getchildat(i);
   child.clearanimation();
   int index = position + i;
   child = miadapter.getitemview(child, (index >= miadapter.getcount()) ? (index - miadapter.getcount()) : index);
   if (animate) {
    if (i == childcount - 1) {
     child.setanimation(mlastoneanimation);
    } else {
     child.setanimation(mcommonanimation);
    }
   }
   child.setvisibility(view.visible);
  }
  if (animate) {
   mcommonanimation.startnow();
   mlastoneanimation.startnow();
  }
 
  //保证传入的position小于getcount
  if (mcurrentindex >= miadapter.getcount()) {
   mcurrentindex = 0;
  }
 }
 
 private final int flip_msg = 1;
 
 private final handler mhandler = new handler() {
  @override
  public void handlemessage(message msg) {
   if (msg.what == flip_msg) {
    if (mrunning) {
     showitems(mcurrentindex++, true);
     msg = obtainmessage(flip_msg);
     sendmessagedelayed(msg, mflipinterval);
    }
   }
  }
 };
 
 public interface iadapter {
 
  /**
   * @param convertview
   * @param position
   * @return
   */
  public view getitemview(view convertview, int position);
 
  /**
   * @return 数据count
   */
  public int getcount();
 
 }
 
}

再来看看调用部分:

public class mainactivity extends actionbaractivity implements viewflipper.iadapter {
 
 viewflipper viewflipper;
 
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);
  viewflipper = (viewflipper) findviewbyid(r.id.view_flipper);
  viewflipper.setiadapter(this);
 }
 
 @override
 protected void onresume() {
  super.onresume();
  viewflipper.startflipping();
 }
 
 @override
 public view getitemview(view convertview, int position) {
  view item = null;
  textview textview;
  if (convertview == null) {
   item = view.inflate(this, r.layout.item, null);
  } else {
   item = convertview;
  }
  textview = (textview) item.findviewbyid(r.id.textview);
  textview.settext("测试数据:" + position);
  return item;
 }
 
 @override
 public int getcount() {
  return 8;
 }
}

可以看出,mainactivity实现了viewflipper.iadapter接口,setadapter后调用startflipper即可。

这里布局文件我就不贴出来了,附上工程源码,项目里动画时间有点长,修改下就ok。

限于水平有限,不足之处难免,望各位不舍指正,与君共勉。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。