Android開(kāi)發(fā)實(shí)現(xiàn)帶有反彈效果仿IOS反彈scrollview教程詳解
首先給大家看一下我們今天這個(gè)最終實(shí)現(xiàn)的效果圖:
這個(gè)是ios中的反彈效果。當(dāng)然我們安卓中如果想要實(shí)現(xiàn)這種效果,感覺(jué)不會(huì)那么生硬,滾動(dòng)到底部或者頂部的時(shí)候。當(dāng)然
使用scrollview是無(wú)法實(shí)現(xiàn)的。所以我們需要新建一個(gè)view繼承ScrollView
package davidbouncescrollview.qq986945193.com.davidbouncescrollview; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.TranslateAnimation; import android.widget.ScrollView; /** * @author :程序員小冰 * @新浪微博 :http://weibo.com/mcxiaobing * @GitHub:https://github.com/QQ986945193 * @CSDN博客: http://blog.csdn.net/qq_21376985 * @交流Qq :986945193 * 類(lèi)名:帶有反彈效果的scrollview */ public class BounceScrollView extends ScrollView { private View inner;// 孩子View private float y;// 點(diǎn)擊時(shí)y坐標(biāo) private Rect normal = new Rect();// 矩形(這里只是個(gè)形式,只是用于判斷是否需要?jiǎng)赢?huà).) private boolean isCount = false;// 是否開(kāi)始計(jì)算 public BounceScrollView(Context context, AttributeSet attrs) { super(context, attrs); } /*** * 根據(jù) XML 生成視圖工作完成.該函數(shù)在生成視圖的最后調(diào)用,在所有子視圖添加完之后. 即使子類(lèi)覆蓋了 onFinishInflate * 方法,也應(yīng)該調(diào)用父類(lèi)的方法,使該方法得以執(zhí)行. */ @SuppressLint("MissingSuperCall") @Override protected void onFinishInflate() { if (getChildCount() > 0) { inner = getChildAt(0); } } /*** * 監(jiān)聽(tīng)touch */ @Override public boolean onTouchEvent(MotionEvent ev) { if (inner != null) { commOnTouchEvent(ev); } return super.onTouchEvent(ev); } /*** * 觸摸事件 * * @param ev */ public void commOnTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_UP: // 手指松開(kāi). if (isNeedAnimation()) { animation(); isCount = false; } break; /*** * 排除出第一次移動(dòng)計(jì)算,因?yàn)榈谝淮螣o(wú)法得知y坐標(biāo), 在MotionEvent.ACTION_DOWN中獲取不到, * 因?yàn)榇藭r(shí)是MyScrollView的touch事件傳遞到到了LIstView的孩子item上面.所以從第二次計(jì)算開(kāi)始. * 然而我們也要進(jìn)行初始化,就是第一次移動(dòng)的時(shí)候讓滑動(dòng)距離歸0. 之后記錄準(zhǔn)確了就正常執(zhí)行. * https://github.com/QQ986945193 */ case MotionEvent.ACTION_MOVE: final float preY = y;// 按下時(shí)的y坐標(biāo) float nowY = ev.getY();// 時(shí)時(shí)y坐標(biāo) int deltaY = (int) (preY - nowY);// 滑動(dòng)距離 if (!isCount) { deltaY = 0; // 在這里要?dú)w0. } y = nowY; // 當(dāng)滾動(dòng)到最上或者最下時(shí)就不會(huì)再滾動(dòng),這時(shí)移動(dòng)布局 if (isNeedMove()) { // 初始化頭部矩形 if (normal.isEmpty()) { // 保存正常的布局位置 normal.set(inner.getLeft(), inner.getTop(), inner.getRight(), inner.getBottom()); } // Log.e("jj", "矩形:" + inner.getLeft() + "," + inner.getTop() // + "," + inner.getRight() + "," + inner.getBottom()); // 移動(dòng)布局 inner.layout(inner.getLeft(), inner.getTop() - deltaY / 2, inner.getRight(), inner.getBottom() - deltaY / 2); } isCount = true; break; default: break; } } /*** * 回縮動(dòng)畫(huà) */ public void animation() { // 開(kāi)啟移動(dòng)動(dòng)畫(huà) TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(), normal.top); ta.setDuration(200); inner.startAnimation(ta); // 設(shè)置回到正常的布局位置 inner.layout(normal.left, normal.top, normal.right, normal.bottom); // Log.e("jj", "回歸:" + normal.left + "," + normal.top + "," + normal.right // + "," + normal.bottom); normal.setEmpty(); } // 是否需要開(kāi)啟動(dòng)畫(huà) public boolean isNeedAnimation() { return !normal.isEmpty(); } /*** * 是否需要移動(dòng)布局 inner.getMeasuredHeight():獲取的是控件的總高度 * <p/> * getHeight():獲取的是屏幕的高度 * <p/> * https://github.com/QQ986945193 * * @return */ public boolean isNeedMove() { int offset = inner.getMeasuredHeight() - getHeight(); int scrollY = getScrollY(); // Log.e("jj", "scrolly=" + scrollY); // 0是頂部,后面那個(gè)是底部 if (scrollY == 0 || scrollY == offset) { return true; } return false; } }
然后他的用法就是和ScrollView用法一樣了。比如直接在布局中引用:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="davidbouncescrollview.qq986945193.com.davidbouncescrollview.MainActivity"> <davidbouncescrollview.qq986945193.com.davidbouncescrollview.BounceScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/black" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="大家好,我是程序員小冰" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/black" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="大家好,我是程序員小冰" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/black" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="大家好,我是程序員小冰" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/black" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="大家好,我是程序員小冰" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/black" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="大家好,我是程序員小冰" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/black" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="大家好,我是程序員小冰" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/black" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="大家好,我是程序員小冰" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@android:color/black" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="大家好,我是程序員小冰" /> </LinearLayout> </davidbouncescrollview.qq986945193.com.davidbouncescrollview.BounceScrollView> </LinearLayout>
最后直接運(yùn)行即可看到上面的效果。
(AndroidStudio版)github下載地址:
https://github.com/QQ986945193/DavidBounceScrollView
以上所述是小編給大家介紹的Android開(kāi)發(fā)實(shí)現(xiàn)帶有反彈效果仿IOS反彈scrollview教程詳解,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Android實(shí)現(xiàn)微信自動(dòng)搶紅包的程序
簡(jiǎn)單實(shí)現(xiàn)了微信自動(dòng)搶紅包的服務(wù),原理就是根據(jù)關(guān)鍵字找到相應(yīng)的View, 然后自動(dòng)點(diǎn)擊,接下來(lái)通過(guò)本文給大家介紹Android實(shí)現(xiàn)微信自動(dòng)搶紅包的程序,對(duì)android微信自動(dòng)搶紅包相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-02-02Android實(shí)現(xiàn)發(fā)送短信功能實(shí)例詳解
這篇文章主要介紹了Android實(shí)現(xiàn)發(fā)送短信功能的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android實(shí)現(xiàn)發(fā)送短信的原理、步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-02-02Android 控件(button)對(duì)齊方法實(shí)現(xiàn)詳解
horizontal是讓所有的子元素按水平方向從左到右排列,vertical是讓所有的子元素按豎直方向從上到下排列,下面為大家介紹下控件(button)的對(duì)齊方法2013-06-06詳解Android 在 ViewPager 中使用 Fragment 的懶加載
本篇文章主要介紹了Android 在 ViewPager 中使用 Fragment 的懶加載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Android開(kāi)發(fā)服務(wù)Service全面講解
Android的服務(wù)是開(kāi)發(fā)Android應(yīng)用程序的重要組成部分。不同于活動(dòng)Activity,服務(wù)是在后臺(tái)運(yùn)行,服務(wù)沒(méi)有接口,生命周期也與活動(dòng)Activity非常不同。通過(guò)使用服務(wù)我們可以實(shí)現(xiàn)一些后臺(tái)操作,比如想從遠(yuǎn)程服務(wù)器加載一個(gè)網(wǎng)頁(yè)等,下面來(lái)看看詳細(xì)內(nèi)容,需要的朋友可以參考下2023-02-02android自定義view用path畫(huà)長(zhǎng)方形
這篇文章主要為大家詳細(xì)介紹了android自定義view用path畫(huà)長(zhǎng)方形,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04Android頁(yè)面之間進(jìn)行數(shù)據(jù)回傳的方法分析
這篇文章主要介紹了Android頁(yè)面之間進(jìn)行數(shù)據(jù)回傳的方法,結(jié)合實(shí)例形式分析了Android頁(yè)面之間進(jìn)行數(shù)據(jù)的傳遞與處理技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06Android數(shù)據(jù)類(lèi)型之間相互轉(zhuǎn)換系統(tǒng)介紹
一些初學(xué)Android的朋友可能會(huì)遇到JAVA的數(shù)據(jù)類(lèi)型之間轉(zhuǎn)換的苦惱;本文將為有這類(lèi)需求的朋友解決此類(lèi)問(wèn)題2012-11-11Android開(kāi)發(fā)之使用ExifInterface獲取拍照后的圖片屬性
這篇文章主要介紹了Android開(kāi)發(fā)之使用ExifInterface獲取拍照后的圖片屬性,較為詳細(xì)的分析了ExifInterface類(lèi)操作圖片的具體使用技巧,需要的朋友可以參考下2016-01-01