首页 > 系统 > iOS > 正文

仿IOS效果 带弹簧动画的ListView

2020-07-26 03:30:15
字体:
来源:转载
供稿:网友

最近项目打算做一个界面,类似于dayone首页的界面效果,dayone 是一款付费应用,目前只有IOS端。作为一个资深懒惰的程序员,奉行的宗旨是绝对不重复造一个轮子。于是乎,去网上找一大堆开源项目,发现没有找到合适的,然后,只能硬着头皮自己来了。先看看效果:


效果图

其实写起来也比较简单,就是控制ListView的头部和底部的高度就可以了, 如果用RecycleView实现起来也是一样,只是RecycleView添加头和尾巴稍微麻烦一点,处理点击事件也不是很方便,所以就基于ListView去实现了。实现的代码, 我已经上传到github上了。

1、使用方法

compile 'com.a520wcf.yllistview:YLListView:1.0.1

2、使用介绍:
1)、布局:
布局注意一个小细节android:layout_height 最好是match_parent, 否则ListView每次滑动的时候都有可能需要重新计算条目高度,比较耗费CPU;

 <com.a520wcf.yllistview.YLListView  android:divider="@android:color/transparent" android:id="@+id/listView"  android:layout_width="match_parent"  android:layout_height="match_parent" />

2)、代码:

 private YLListView listView; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  listView = (YLListView) findViewById(R.id.listView);  // 不添加也有默认的头和底  View topView=View.inflate(this,R.layout.top,null);  listView.addHeaderView(topView);  View bottomView=new View(getApplicationContext());  listView.addFooterView(bottomView);  // 顶部和底部也可以固定最终的高度 不固定就使用布局本身的高度  listView.setFinalBottomHeight(100);  listView.setFinalTopHeight(100);  listView.setAdapter(new DemoAdapter());  //YLListView默认有头和底 处理点击事件位置注意减去  listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {   @Override   public void onItemClick(AdapterView<?> parent, View view, int position, long id) {    position=position-listView.getHeaderViewsCount();   }  }); }


3、源码介绍
其实这个项目里面只有一个类,大家不需要依赖,直接把这个类复制到项目中就可以了,来看看源码:

package com.a520wcf.yllistview;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewTreeObserver.OnGlobalLayoutListener;import android.view.animation.DecelerateInterpolator;import android.widget.AbsListView;import android.widget.ListView;import android.widget.Scroller;public class YLListView extends ListView implements AbsListView.OnScrollListener { private Scroller mScroller; // used for scroll back private float mLastY = -1; private int mScrollBack; private final static int SCROLLBACK_HEADER = 0; private final static int SCROLLBACK_FOOTER = 1; private final static int SCROLL_DURATION = 400; // scroll back duration private final static float OFFSET_RADIO = 1.8f; // total list items, used to detect is at the bottom of ListView. private int mTotalItemCount; private View mHeaderView; // 顶部图片 private View mFooterView; // 底部图片 private int finalTopHeight; private int finalBottomHeight; public YLListView(Context context) {  super(context);  initWithContext(context); } public YLListView(Context context, AttributeSet attrs) {  super(context, attrs);  initWithContext(context); } public YLListView(Context context, AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle);  initWithContext(context); } private void initWithContext(Context context) {  mScroller = new Scroller(context, new DecelerateInterpolator());  super.setOnScrollListener(this);  this.getViewTreeObserver().addOnGlobalLayoutListener(    new OnGlobalLayoutListener() {     @Override     public void onGlobalLayout() {      if(mHeaderView==null){       View view=new View(getContext());       addHeaderView(view);      }      if(mFooterView==null){       View view=new View(getContext());       addFooterView(view);      }      getViewTreeObserver()        .removeGlobalOnLayoutListener(this);     }    }); } @Override public boolean onTouchEvent(MotionEvent ev) {  if (mLastY == -1) {   mLastY = ev.getRawY();  }  switch (ev.getAction()) {   case MotionEvent.ACTION_DOWN:    mLastY = ev.getRawY();    break;   case MotionEvent.ACTION_MOVE:    final float deltaY = ev.getRawY() - mLastY;    mLastY = ev.getRawY();    if (getFirstVisiblePosition() == 0 && (mHeaderView.getHeight() > finalTopHeight || deltaY > 0)      && mHeaderView.getTop() >= 0) {     // the first item is showing, header has shown or pull down.     updateHeaderHeight(deltaY / OFFSET_RADIO);    } else if (getLastVisiblePosition() == mTotalItemCount - 1      && (getFootHeight() >finalBottomHeight || deltaY < 0)) {     updateFooterHeight(-deltaY / OFFSET_RADIO);    }    break;   default:    mLastY = -1; // reset    if (getFirstVisiblePosition() == 0 && getHeaderHeight() > finalTopHeight) {     resetHeaderHeight();    }    if (getLastVisiblePosition() == mTotalItemCount - 1 ){      if(getFootHeight() > finalBottomHeight) {       resetFooterHeight();      }    }    break;  }  return super.onTouchEvent(ev); } /**  * 重置底部高度  */ private void resetFooterHeight() {  int bottomHeight = getFootHeight();  if (bottomHeight > finalBottomHeight) {   mScrollBack = SCROLLBACK_FOOTER;   mScroller.startScroll(0, bottomHeight, 0, -bottomHeight+finalBottomHeight,     SCROLL_DURATION);   invalidate();  } } // 计算滑动 当invalidate()后 系统会自动调用 @Override public void computeScroll() {  if (mScroller.computeScrollOffset()) {   if (mScrollBack == SCROLLBACK_HEADER) {    setHeaderHeight(mScroller.getCurrY());   } else {    setFooterViewHeight(mScroller.getCurrY());   }   postInvalidate();  }  super.computeScroll(); } // 设置顶部高度 private void setHeaderHeight(int height) {  LayoutParams layoutParams = (LayoutParams) mHeaderView.getLayoutParams();  layoutParams.height = height;  mHeaderView.setLayoutParams(layoutParams); } // 设置底部高度 private void setFooterViewHeight(int height) {  LayoutParams layoutParams =    (LayoutParams) mFooterView.getLayoutParams();  layoutParams.height =height;  mFooterView.setLayoutParams(layoutParams); } // 获取顶部高度 public int getHeaderHeight() {  AbsListView.LayoutParams layoutParams =    (AbsListView.LayoutParams) mHeaderView.getLayoutParams();  return layoutParams.height; } // 获取底部高度 public int getFootHeight() {  AbsListView.LayoutParams layoutParams =    (AbsListView.LayoutParams) mFooterView.getLayoutParams();  return layoutParams.height; } private void resetHeaderHeight() {  int height = getHeaderHeight();  if (height == 0) // not visible.   return;  mScrollBack = SCROLLBACK_HEADER;  mScroller.startScroll(0, height, 0, finalTopHeight - height,    SCROLL_DURATION);  invalidate(); } /**  * 设置顶部高度 如果不设置高度,默认就是布局本身的高度  * @param height 顶部高度  */ public void setFinalTopHeight(int height) {  this.finalTopHeight = height; } /**  * 设置底部高度 如果不设置高度,默认就是布局本身的高度  * @param height 底部高度  */ public void setFinalBottomHeight(int height){  this.finalBottomHeight=height; } @Override public void addHeaderView(View v) {  mHeaderView = v;  super.addHeaderView(mHeaderView);  mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(    new OnGlobalLayoutListener() {     @Override     public void onGlobalLayout() {      if(finalTopHeight==0) {       finalTopHeight = mHeaderView.getMeasuredHeight();      }      setHeaderHeight(finalTopHeight);      getViewTreeObserver()        .removeGlobalOnLayoutListener(this);     }    }); } @Override public void addFooterView(View v) {  mFooterView = v;  super.addFooterView(mFooterView);  mFooterView.getViewTreeObserver().addOnGlobalLayoutListener(    new OnGlobalLayoutListener() {     @Override     public void onGlobalLayout() {      if(finalBottomHeight==0) {       finalBottomHeight = mFooterView.getMeasuredHeight();      }      setFooterViewHeight(finalBottomHeight);      getViewTreeObserver()        .removeGlobalOnLayoutListener(this);     }    }); } private OnScrollListener mScrollListener; // user's scroll listener @Override public void setOnScrollListener(OnScrollListener l) {  mScrollListener = l; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) {  if (mScrollListener != null) {   mScrollListener.onScrollStateChanged(view, scrollState);  } } @Override public void onScroll(AbsListView view, int firstVisibleItem,       int visibleItemCount, int totalItemCount) {  // send to user's listener  mTotalItemCount = totalItemCount;  if (mScrollListener != null) {   mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,     totalItemCount);  } } private void updateHeaderHeight(float delta) {  setHeaderHeight((int) (getHeaderHeight()+delta));  setSelection(0); // scroll to top each time } private void updateFooterHeight(float delta) {  setFooterViewHeight((int) (getFootHeight()+delta)); }}

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表