国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > iOS > 正文

仿IOS效果 帶彈簧動(dòng)畫(huà)的ListView

2020-07-26 03:30:15
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

最近項(xiàng)目打算做一個(gè)界面,類(lèi)似于dayone首頁(yè)的界面效果,dayone 是一款付費(fèi)應(yīng)用,目前只有IOS端。作為一個(gè)資深懶惰的程序員,奉行的宗旨是絕對(duì)不重復(fù)造一個(gè)輪子。于是乎,去網(wǎng)上找一大堆開(kāi)源項(xiàng)目,發(fā)現(xiàn)沒(méi)有找到合適的,然后,只能硬著頭皮自己來(lái)了。先看看效果:


效果圖

其實(shí)寫(xiě)起來(lái)也比較簡(jiǎn)單,就是控制ListView的頭部和底部的高度就可以了, 如果用RecycleView實(shí)現(xiàn)起來(lái)也是一樣,只是RecycleView添加頭和尾巴稍微麻煩一點(diǎn),處理點(diǎn)擊事件也不是很方便,所以就基于ListView去實(shí)現(xiàn)了。實(shí)現(xiàn)的代碼, 我已經(jīng)上傳到github上了。

1、使用方法

compile 'com.a520wcf.yllistview:YLListView:1.0.1

2、使用介紹:
1)、布局:
布局注意一個(gè)小細(xì)節(jié)android:layout_height 最好是match_parent, 否則ListView每次滑動(dòng)的時(shí)候都有可能需要重新計(jì)算條目高度,比較耗費(fèi)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);  // 不添加也有默認(rèn)的頭和底  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默認(rèn)有頭和底 處理點(diǎn)擊事件位置注意減去  listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {   @Override   public void onItemClick(AdapterView<?> parent, View view, int position, long id) {    position=position-listView.getHeaderViewsCount();   }  }); }


3、源碼介紹
其實(shí)這個(gè)項(xiàng)目里面只有一個(gè)類(lèi),大家不需要依賴,直接把這個(gè)類(lèi)復(fù)制到項(xiàng)目中就可以了,來(lái)看看源碼:

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();  } } // 計(jì)算滑動(dòng) 當(dāng)invalidate()后 系統(tǒng)會(huì)自動(dòng)調(diào)用 @Override public void computeScroll() {  if (mScroller.computeScrollOffset()) {   if (mScrollBack == SCROLLBACK_HEADER) {    setHeaderHeight(mScroller.getCurrY());   } else {    setFooterViewHeight(mScroller.getCurrY());   }   postInvalidate();  }  super.computeScroll(); } // 設(shè)置頂部高度 private void setHeaderHeight(int height) {  LayoutParams layoutParams = (LayoutParams) mHeaderView.getLayoutParams();  layoutParams.height = height;  mHeaderView.setLayoutParams(layoutParams); } // 設(shè)置底部高度 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(); } /**  * 設(shè)置頂部高度 如果不設(shè)置高度,默認(rèn)就是布局本身的高度  * @param height 頂部高度  */ public void setFinalTopHeight(int height) {  this.finalTopHeight = height; } /**  * 設(shè)置底部高度 如果不設(shè)置高度,默認(rèn)就是布局本身的高度  * @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)); }}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 淮滨县| 尼木县| 江北区| 凉山| 海城市| 宝鸡市| 扬中市| 九龙县| 锡林郭勒盟| 彰化市| 三明市| 乐安县| 广饶县| 正宁县| 宁远县| 柳河县| 合作市| 海盐县| 聂拉木县| 长寿区| 平顺县| 天峨县| 阳泉市| 随州市| 华池县| 花垣县| 昭通市| 木兰县| 安福县| 宁远县| 长乐市| 开原市| 锡林郭勒盟| 米泉市| 榕江县| 顺昌县| 汤原县| 长沙市| 天全县| 维西| 凤山市|