Android自定義ViewGroup實現(xiàn)彈性滑動效果
自定義View實現(xiàn)一個彈性滑動的效果,供大家參考,具體內(nèi)容如下


實現(xiàn)原理
onMeasure()中測量所有子View
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 測量所有子View
int count = getChildCount();
for (int i = 0; i < count; i++) {
View childView = getChildAt(i);
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
}
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
onLayout()中,將所有的子View按照位置依次往下排列
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 設置ViewGroup的高度,對所有子View進行排列
int childCount = getChildCount();
MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
params.height = mScreenHeight * childCount;
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
if (childView.getVisibility() != View.GONE) {
// 給每個ChildView放置在指定位置
childView.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);
}
}
}
onTouchEvent()中處理滑動
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastY = (int) event.getY();
mStart = getScrollY();
return true;
case MotionEvent.ACTION_MOVE:
if (!mScroller.isFinished()) {
// 終止滑動
mScroller.abortAnimation();
}
int offsetY = (int) (mLastY - event.getY());
Log.d(TAG, "onTouchEvent: getScrollY: " + getScrollY());
Log.d(TAG, "onTouchEvent: offsetY " + offsetY);
// 到達頂部,使用offset判斷方向
if (getScrollY() + offsetY < 0) { // 當前已經(jīng)滑動的 Y 位置
offsetY = 0;
}
// 到達底部
if (getScrollY() > getHeight() - mScreenHeight && offsetY > 0) {
offsetY = 0;
}
scrollBy(0, offsetY);
// 滑動完成后,重新設置LastY位置
mLastY = (int) event.getY();
break;
case MotionEvent.ACTION_UP:
mEnd = getScrollY();
int distance = mEnd - mStart;
if (distance > 0) { // 向上滑動
if (distance < mScreenHeight / 3) {
Log.d(TAG, "onTouchEvent: distance < screen/3");
// 回到原來位置
mScroller.startScroll(0, getScrollY(), 0, -distance);
} else {
// 滾到屏幕的剩余位置
mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - distance);
}
} else { // 向下滑動
if (-distance < mScreenHeight / 3) {
mScroller.startScroll(0, getScrollY(), 0, -distance);
} else {
mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight - distance);
}
}
postInvalidate();
}
return super.onTouchEvent(event);
}
其中ACTION_UP這段代碼是處理彈性滑動的
case MotionEvent.ACTION_UP:
mEnd = getScrollY();
int distance = mEnd - mStart;
if (distance > 0) { // 向上滑動
if (distance < mScreenHeight / 3) {
Log.d(TAG, "onTouchEvent: distance < screen/3");
// 回到原來位置
mScroller.startScroll(0, getScrollY(), 0, -distance);
} else {
// 滾到屏幕的剩余位置
mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - distance);
}
} else { // 向下滑動
if (-distance < mScreenHeight / 3) {
mScroller.startScroll(0, getScrollY(), 0, -distance);
} else {
mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight - distance);
}
}
postInvalidate();
完整代碼
public class ScrollViewGroup extends ViewGroup {
private static final String TAG = "ScrollView";
private Scroller mScroller;
private int mScreenHeight; // 窗口高度
private int mLastY;
private int mStart;
private int mEnd;
public ScrollViewGroup(Context context) {
this(context, null);
}
public ScrollViewGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScrollViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mScroller = new Scroller(context);
// 獲取屏幕高度
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(metrics);
mScreenHeight = metrics.heightPixels;
Log.d(TAG, "ScrollViewGroup: ScreenHeight " + mScreenHeight);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 測量所有子View
int count = getChildCount();
for (int i = 0; i < count; i++) {
View childView = getChildAt(i);
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
}
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 設置ViewGroup的高度,對所有子View進行排列
int childCount = getChildCount();
MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
params.height = mScreenHeight * childCount;
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
if (childView.getVisibility() != View.GONE) {
// 給每個ChildView放置在指定位置
childView.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastY = (int) event.getY();
mStart = getScrollY();
return true;
case MotionEvent.ACTION_MOVE:
if (!mScroller.isFinished()) {
// 終止滑動
mScroller.abortAnimation();
}
int offsetY = (int) (mLastY - event.getY());
Log.d(TAG, "onTouchEvent: getScrollY: " + getScrollY());
Log.d(TAG, "onTouchEvent: offsetY " + offsetY);
// 到達頂部,使用offset判斷方向
if (getScrollY() + offsetY < 0) { // 當前已經(jīng)滑動的 Y 位置
offsetY = 0;
}
// 到達底部
if (getScrollY() > getHeight() - mScreenHeight && offsetY > 0) {
offsetY = 0;
}
scrollBy(0, offsetY);
// 滑動完成后,重新設置LastY位置
mLastY = (int) event.getY();
break;
case MotionEvent.ACTION_UP:
mEnd = getScrollY();
int distance = mEnd - mStart;
if (distance > 0) { // 向上滑動
if (distance < mScreenHeight / 3) {
Log.d(TAG, "onTouchEvent: distance < screen/3");
// 回到原來位置
mScroller.startScroll(0, getScrollY(), 0, -distance);
} else {
// 滾到屏幕的剩余位置
mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - distance);
}
} else { // 向下滑動
if (-distance < mScreenHeight / 3) {
mScroller.startScroll(0, getScrollY(), 0, -distance);
} else {
mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight - distance);
}
}
postInvalidate();
}
return super.onTouchEvent(event);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- android開發(fā)通過Scroller實現(xiàn)過渡滑動效果操作示例
- Android使用Scroller實現(xiàn)彈性滑動效果
- Android自定義View彈性滑動Scroller詳解
- Android用Scroller實現(xiàn)一個可向上滑動的底部導航欄
- 詳解Android應用開發(fā)中Scroller類的屏幕滑動功能運用
- Android Scroll實現(xiàn)彈性滑動_列表下拉彈性滑動的示例代碼
- android自定義ViewPager水平滑動彈性效果
- Android使用Handler實現(xiàn)View彈性滑動
- Android?Scroller實現(xiàn)彈性滑動效果
相關文章
android studio3.0.1無法啟動Gradle守護進程的解決方法
這篇文章主要為大家詳細介紹了android studio3.0.1無法啟動Gradle守護進程的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-08-08
Android獲取arrays.xml里的數(shù)組字段值實例詳解
這篇文章主要介紹了Android獲取arrays.xml里的數(shù)組字段值實例詳解的相關資料,需要的朋友可以參考下2017-04-04
Android之日期時間選擇控件DatePicker和TimePicker實例
本篇文章主要介紹了Android之日期時間選擇控件DatePicker和TimePicker實例,具有一定的參考價值,有興趣的可以了解一下2017-05-05
一文帶你看懂Android Application啟動流程是怎樣的
談到Android Application的啟動流程,很多文章都是各種源碼類和方法的一堆調(diào)用關系,這樣的文章就算看一百遍,也只是云里霧里。源碼得看,但是最好不要一下子深陷到源碼的細節(jié)之中,不可自拔。這里站在前人的基礎之上做一個總結2021-10-10
Android自定義View實現(xiàn)圓環(huán)進度條
這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)圓環(huán)進度條,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05
Android多線程斷點續(xù)傳下載功能實現(xiàn)代碼
這篇文章主要為大家詳細介紹了Android多線程斷點續(xù)傳下載功能的實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03
Android中實現(xiàn)根據(jù)資源名獲取資源ID
這篇文章主要介紹了Android中實現(xiàn)根據(jù)資源名獲取資源ID,本文講解了使用文件名獲取資源ID的方法,需要的朋友可以參考下2015-01-01

