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

效果圖
其實寫起來也比較簡單,就是控制ListView的頭部和底部的高度就可以了, 如果用RecycleView實現(xiàn)起來也是一樣,只是RecycleView添加頭和尾巴稍微麻煩一點,處理點擊事件也不是很方便,所以就基于ListView去實現(xiàn)了。實現(xiàn)的代碼, 我已經(jīng)上傳到github上了。
1、使用方法
compile 'com.a520wcf.yllistview:YLListView:1.0.1
2、使用介紹:
1)、布局:
布局注意一個小細節(jié)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()后 系統(tǒng)會自動調用
@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));
}
}
以上就是本文的全部內容,希望對大家的學習有所幫助。
相關文章
IOS開發(fā)UIPasteboard類的粘貼板全面詳解
這篇文章主要為大家介紹了IOS開發(fā)UIPasteboard類的粘貼板全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06
iOS利用攝像頭獲取環(huán)境光感參數(shù)的方法
本篇文章主要介紹了iOS利用攝像頭獲取環(huán)境光感參數(shù)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
iOS UIScrollView滾動視圖/無限循環(huán)滾動/自動滾動的實例代碼
這篇文章主要介紹了iOS UIScrollView滾動視圖/無限循環(huán)滾動/自動滾動,需要的朋友可以參考下2017-02-02

