Android通過overScrollBy實(shí)現(xiàn)下拉視差特效
overScrollBy實(shí)現(xiàn)下拉視差特效,效果圖如下
先來分析overScrollBy方法的使用,它是View的方法,參數(shù)有點(diǎn)多:
/** * 當(dāng)滑動(dòng)的超出上,下,左,右最大范圍時(shí)回調(diào) * * @param deltaX x方向的瞬時(shí)偏移量,左邊到頭,向右拉為負(fù),右邊到頭,向左拉為正 * @param deltaY y方向的瞬時(shí)偏移量,頂部到頭,向下拉為負(fù),底部到頭,向上拉為正 * @param scrollX 水平方向的永久偏移量 * @param scrollY 豎直方向的永久偏移量 * @param scrollRangeX 水平方向滑動(dòng)的范圍 * @param scrollRangeY 豎直方向滑動(dòng)的范圍 * @param maxOverScrollX 水平方向最大滑動(dòng)范圍 * @param maxOverScrollY 豎直方向最大滑動(dòng)范圍 * @param isTouchEvent 是否是手指觸摸滑動(dòng), true為手指, false為慣性 * @return */ @Override protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) { return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); }
大致步驟如下:
1.這整體是一個(gè)ListView,所以需要自定義一個(gè)ListView.
2.處理頭部布局文件,將其以HeaderView的方式添加到自定義的ListView中
3.需要獲取HeaderView的ImageView的初始高度和ImageView中圖片的高度.因?yàn)檫@2個(gè)高度將決定下來的時(shí)候圖片拉出的范圍,以及松手后圖片回彈的動(dòng)畫效果.對(duì)應(yīng)控件寬高的獲取,有興趣的可以看這篇文章淺談自定義View的寬高獲取
4.在overScrollBy方法內(nèi)通過修改ImageView的LayoutParams的height值來顯示更多的圖片內(nèi)容.
5.在onTouchEvent方法內(nèi)處理ACTION_UP事件,使ImageView有回彈的動(dòng)畫效果,這里介紹2種方式,分別是屬性動(dòng)畫和自定義動(dòng)畫.
好了,先來看HeaderView的布局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="160dp" <span style="color:#ff0000;">android:scaleType="centerCrop"</span> android:src="@drawable/header" /> </LinearLayout>
沒什么特別的,就是一個(gè)ImageView,通過src設(shè)置了一張圖片,這里唯一要將的就是scaleType屬性,我這邊設(shè)置了centerCrop,以圖片的最小的邊開始截取,因?yàn)檫@里選擇的圖片是高度大于寬度的,所以裁剪的時(shí)候會(huì)保留完整的寬度,中心裁剪,如下圖所示:
自定義ListView代碼,整體代碼還是比較簡短的.
/** * Created by mChenys on 2015/12/23. */ public class MyListView extends ListView { private ImageView mHeaderIv; //HeaderView 的ImageView private int mOriginalHeight; //最初ImageView的高度 private int mDrawableHeight;//ImageView中圖片的高度 public MyListView(Context context) { this(context, null); } public MyListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } /** * 設(shè)置頭部和獲取高度信息 */ private void init() { //初始化頭部文件 View headerView = View.inflate(getContext(), R.layout.view_header, null); mHeaderIv = (ImageView) headerView.findViewById(R.id.imageView); //將其添加到ListView的頭部 addHeaderView(headerView); //通過設(shè)置監(jiān)聽來獲取控件的高度 mHeaderIv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public void onGlobalLayout() { //只需監(jiān)聽一次,否則之后的onLayout方法回調(diào)的時(shí)候還是會(huì)回調(diào)這里 mHeaderIv.getViewTreeObserver().removeOnGlobalLayoutListener(this); mOriginalHeight = mHeaderIv.getMeasuredHeight();//獲取ImageView的初始高度 mDrawableHeight = mHeaderIv.getDrawable().getIntrinsicHeight();//獲取ImageView中圖片的高度 } }); //去掉下拉到頭部后的藍(lán)色線 setOverScrollMode(OVER_SCROLL_NEVER); } /** * 當(dāng)滑動(dòng)的超出上,下,左,右最大范圍時(shí)回調(diào) * * @param deltaX x方向的瞬時(shí)偏移量,左邊到頭,向右拉為負(fù),右邊到頭,向左拉為正 * @param deltaY y方向的瞬時(shí)偏移量,頂部到頭,向下拉為負(fù),底部到頭,向上拉為正 * @param scrollX 水平方向的永久偏移量 * @param scrollY 豎直方向的永久偏移量 * @param scrollRangeX 水平方向滑動(dòng)的范圍 * @param scrollRangeY 豎直方向滑動(dòng)的范圍 * @param maxOverScrollX 水平方向最大滑動(dòng)范圍 * @param maxOverScrollY 豎直方向最大滑動(dòng)范圍 * @param isTouchEvent 是否是手指觸摸滑動(dòng), true為手指, false為慣性 * @return */ @Override protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) { // 手指拉動(dòng)并且是下拉 if (isTouchEvent && deltaY < 0) { // 把拉動(dòng)的瞬時(shí)變化量的絕對(duì)值交給Header, 就可以實(shí)現(xiàn)放大效果 if (mHeaderIv.getHeight() <= mDrawableHeight) { // 高度不超出圖片最大高度時(shí),才讓其生效 int newHeight = (int) (mHeaderIv.getHeight() + Math.abs(deltaY / 3.0f));//這里除以3是為了達(dá)到視差的效果 mHeaderIv.getLayoutParams().height = newHeight; //此方法必須調(diào)用,調(diào)用后會(huì)重新調(diào)用onMeasure和onLayout方法進(jìn)行測量和定位 mHeaderIv.requestLayout(); } } return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_UP: // 執(zhí)行回彈動(dòng)畫, 方式一: 屬性動(dòng)畫\值動(dòng)畫 //獲取ImageView在松手時(shí)的高度 int currHeight = mHeaderIv.getHeight(); // 從當(dāng)前高度mHeaderIv.getHeight(), 執(zhí)行動(dòng)畫到原始高度mOriginalHeight ValueAnimator animator = ValueAnimator.ofInt(currHeight, mOriginalHeight); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int value = (int) animation.getAnimatedValue(); mHeaderIv.getLayoutParams().height = value; //此方法必須調(diào)用,調(diào)用后會(huì)重新調(diào)用onMeasure和onLayout方法進(jìn)行測量和定位 mHeaderIv.requestLayout(); } }); animator.setDuration(500); animator.setInterpolator(new OvershootInterpolator()); animator.start(); //方式二,通過自定義動(dòng)畫 /*ResetAnimation animation = new ResetAnimation(mHeaderIv, mHeaderIv.getHeight(), mOriginalHeight); startAnimation(animation);*/ break; } return super.onTouchEvent(ev); } }
看看自定義動(dòng)畫:
/** * 自定義動(dòng)畫 * Created by mChenys on 2015/12/24. */ public class ResetAnimation extends Animation { private final ImageView headerIv; //要執(zhí)行動(dòng)畫的目標(biāo)ImageView private final int startHeight;//執(zhí)行動(dòng)畫的開始時(shí)的高度 private final int endHeight;//執(zhí)行動(dòng)畫結(jié)束時(shí)的高度 private IntEvaluator mEvaluator; //整型估值器 /** * 構(gòu)造方法初始化 * * @param headerIv 應(yīng)用動(dòng)畫的目標(biāo)控件 * @param startHeight 開始的高度 * @param endHeight 結(jié)束的高度 */ public ResetAnimation(ImageView headerIv, int startHeight, int endHeight) { this.headerIv = headerIv; this.startHeight = startHeight; this.endHeight = endHeight; //定義一個(gè)int類型的類型估值器,用于獲取實(shí)時(shí)變化的高度值 mEvaluator = new IntEvaluator(); //設(shè)置動(dòng)畫持續(xù)時(shí)間 setDuration(500); //設(shè)置插值器 setInterpolator(new OvershootInterpolator()); } /** * 在指定的時(shí)間內(nèi)一直執(zhí)行該方法,直到動(dòng)畫結(jié)束 * interpolatedTime:0-1 標(biāo)識(shí)動(dòng)畫執(zhí)行的進(jìn)度或者百分比 * * @param interpolatedTime * @param t */ @Override protected void applyTransformation(float interpolatedTime, Transformation t) { int currHeight = mEvaluator.evaluate(interpolatedTime, startHeight, endHeight); //通過LayoutParams不斷的改變其高度 headerIv.getLayoutParams().height = currHeight; //此方法必須調(diào)用,調(diào)用后會(huì)重新調(diào)用onMeasure和onLayout方法進(jìn)行測量和定位 headerIv.requestLayout(); } }
MainActivity測試類:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyListView listView = new MyListView(this); listView.setDividerHeight(1); listView.setSelector(new ColorDrawable()); listView.setCacheColorHint(Color.TRANSPARENT); listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, Cheeses.NAMES)); setContentView(listView); } }
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
配置一個(gè)好用的Android模擬器讓你不再對(duì)模擬器那么失望
默認(rèn)情況下的Android模擬器窗口占據(jù)了屏幕巨大的空間,而且毫無緣由的放著一個(gè)屏幕鍵盤,如果你沒親自用過模擬器的話,還有一個(gè)不易發(fā)現(xiàn)的問題:幾乎是慢到不能用2013-01-01TextView長按復(fù)制的實(shí)現(xiàn)方法(總結(jié))
下面小編就為大家?guī)硪黄猅extView長按復(fù)制的實(shí)現(xiàn)方法(總結(jié))。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04android開發(fā)基礎(chǔ)教程—打電話發(fā)短信
打電話發(fā)短信的功能已經(jīng)離不開我們的生活了,記下來介紹打電話發(fā)短信的具體實(shí)現(xiàn)代碼,感興趣的朋友可以了解下2013-01-01Android畫板開發(fā)之添加背景和保存畫板內(nèi)容為圖片
這篇文章主要為大家詳細(xì)介紹了Android畫板開發(fā)之添加背景和保存畫板內(nèi)容為圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12Android實(shí)現(xiàn)底部導(dǎo)航欄功能(選項(xiàng)卡)
這篇文章主要介紹了Android實(shí)現(xiàn)底部導(dǎo)航欄功能,可以隨意切換不同的頁面,實(shí)現(xiàn)選項(xiàng)卡功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-12-12Android XmlPullParser 方式解析 Xml 文檔
這篇文章主要介紹了Android XmlPullParser 方式解析 Xml 文檔的相關(guān)資料,需要的朋友可以參考下2017-06-06Android自定義View原理(實(shí)戰(zhàn))
這篇文章主要介紹了Android自定義View原理,由于Android系統(tǒng)內(nèi)置的View不滿足我們的業(yè)務(wù)需求,變產(chǎn)生了需要自定義View的原因,關(guān)于自定義詳情,需要的小伙伴可以參考下面文章具體詳情2022-05-05android自定義Toast設(shè)定顯示時(shí)間
這篇文章主要為大家詳細(xì)介紹了android自定義Toast設(shè)定顯示時(shí)間,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08