日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

仿IOS效果-带弹簧动画的ListView

發布時間:2025/7/14 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 仿IOS效果-带弹簧动画的ListView 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

背景介紹

最近項目打算做一個界面,類似于dayone首頁的界面效果,dayone 是一款付費應用,目前只有IOS端。作為一個資深懶惰的程序員,奉行的宗旨是絕對不重復造一個輪子。于是乎,去網上找一大堆開源項目,發現沒有找到合適的,然后,只能硬著頭皮自己來了。先看看效果:

其實寫起來也比較簡單,就是控制ListView的頭部和底部的高度就可以了, 如果用RecycleView實現起來也是一樣,只是RecycleView添加頭和尾巴稍微麻煩一點,處理點擊事件也不是很方便,所以就基于ListView去實現了。

實現的代碼, 我已經上傳到github上了。

使用方法

github地址: https://github.com/yll2wcf/YLListView 可以幫我點個star啊~

使用方法

compile 'com.a520wcf.yllistview:YLListView:1.0.1'

使用介紹:

布局:
布局注意一個小細節android:layout_height 最好是match_parent, 否則ListView每次滑動的時候都有可能需要重新計算條目高度,比較耗費CPU;

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

代碼:

private YLListView listView;@Overrideprotected 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() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {position=position-listView.getHeaderViewsCount();}});}

源碼介紹

其實這個項目里面只有一個類,大家不需要依賴,直接把這個類復制到項目中就可以了,來看看源碼:

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;/*** 郵箱 yll@520wcf.com* Created by yull on 12/17.*/ public class YLListView extends ListView implements AbsListView.OnScrollListener {private Scroller mScroller; // used for scroll backprivate 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 durationprivate 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() {@Overridepublic 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);}});}@Overridepublic 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; // resetif (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()后 系統會自動調用@Overridepublic 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;}@Overridepublic void addHeaderView(View v) {mHeaderView = v;super.addHeaderView(mHeaderView);mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {if(finalTopHeight==0) {finalTopHeight = mHeaderView.getMeasuredHeight();}setHeaderHeight(finalTopHeight);getViewTreeObserver().removeGlobalOnLayoutListener(this);}});}@Overridepublic void addFooterView(View v) {mFooterView = v;super.addFooterView(mFooterView);mFooterView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {if(finalBottomHeight==0) {finalBottomHeight = mFooterView.getMeasuredHeight();}setFooterViewHeight(finalBottomHeight);getViewTreeObserver().removeGlobalOnLayoutListener(this);}});}private OnScrollListener mScrollListener; // user's scroll listener@Overridepublic void setOnScrollListener(OnScrollListener l) {mScrollListener = l;}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if (mScrollListener != null) {mScrollListener.onScrollStateChanged(view, scrollState);}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {// send to user's listenermTotalItemCount = 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));} }

轉載于:https://www.cnblogs.com/hehe520/p/6329905.html

總結

以上是生活随笔為你收集整理的仿IOS效果-带弹簧动画的ListView的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。