Android customized viewflipper for scrolling effect

The example of this article is to share the custom view, which is similar to Baidu mobile assistant and the scrolling effect of home page comments@ H_ 502_ 1@

See the effect: @ h_ 502_ 1@

@H_ 502_ 1@@H_ 502_ 1@

Gif doesn't do well. The effect is that several viewitems keep rolling up, and the newly added item has a fade in effect@ H_ 502_ 1@

Let's talk about the implementation idea: the user-defined view inherits to the LinearLayout, controls the number of items and their animation effects, realizes the reuse of items, passes in data, and is easy to use@ H_ 502_ 1@

Code: @ h_ 502_ 1@

/**
 * 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();

 }

}

Let's look at the calling part: @ h_ 502_ 1@

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;
 }
}

As you can see, MainActivity implements the ViewFlipper.IAdapter interface and calls startFlipper after setAdapter. @ H_ 502_ 1@

I won't post the layout file here. I attach the project source code. The animation time in the project is a little long. It's OK to modify it@ H_ 502_ 1@

Limited to the limited level, deficiencies are inevitable. I hope you will not give up correction and encourage me with you@ H_ 502_ 1@

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot@ H_ 502_ 1@

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>