仿IOS效果 帶彈簧動畫的ListView_IOS

來源:互聯網
上載者:User

最近項目打算做一個介面,類似於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)); }}

以上就是本文的全部內容,希望對大家的學習有所協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.