Andoird自定义ViewGroup实现竖向引导界面
生活随笔
收集整理的這篇文章主要介紹了
Andoird自定义ViewGroup实现竖向引导界面
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一般進入APP都有歡迎界面,基本都是水平滾動的,今天和大家分享一個垂直滾動的例子。
先來看看效果把:
首先是布局文件:
<com.example.verticallinearlayout.VerticalLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/id_main_ly" android:layout_width="match_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="#fff" > <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/w02" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="hello" /> </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/w03" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="#fff" android:text="hello" /> </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/w04" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="hello" /> </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/w05" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="hello" /> </RelativeLayout> </com.example.verticallinearlayout.VerticalLinearLayout>自定義的Layout了
package com.example.verticallinearlayout;import android.content.Context; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.Scroller;public class VerticalLinearLayout extends ViewGroup {/*** 屏幕的高度*/private int mScreenHeight;/*** 手指按下時的getScrollY*/private int mScrollStart;/*** 手指抬起時的getScrollY*/private int mScrollEnd;/*** 記錄移動時的Y*/private int mLastY;/*** 滾動的輔助類*/private Scroller mScroller;/*** 是否正在滾動*/private boolean isScrolling;/*** 加速度檢測*/private VelocityTracker mVelocityTracker;/*** 記錄當前頁*/private int currentPage = 0;private OnPageChangeListener mOnPageChangeListener;public VerticalLinearLayout(Context context, AttributeSet attrs){super(context, attrs);/*** 獲得屏幕的高度*/WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);mScreenHeight = outMetrics.heightPixels;// 初始化mScroller = new Scroller(context);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);int count = getChildCount();for (int i = 0; i < count; ++i){View childView = getChildAt(i);measureChild(childView, widthMeasureSpec, heightMeasureSpec);}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b){if (changed){int childCount = getChildCount();// 設置主布局的高度MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();lp.height = mScreenHeight * childCount;setLayoutParams(lp);for (int i = 0; i < childCount; i++){View child = getChildAt(i);if (child.getVisibility() != View.GONE){child.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);// 調用每個自布局的layout}}}}@Overridepublic boolean onTouchEvent(MotionEvent event){// 如果當前正在滾動,調用父類的onTouchEventif (isScrolling)return super.onTouchEvent(event);int action = event.getAction();int y = (int) event.getY();obtainVelocity(event);switch (action){case MotionEvent.ACTION_DOWN:mScrollStart = getScrollY();mLastY = y;break;case MotionEvent.ACTION_MOVE:if (!mScroller.isFinished()){mScroller.abortAnimation();}int dy = mLastY - y;// 邊界值檢查int scrollY = getScrollY();// 已經到達頂端,下拉多少,就往上滾動多少if (dy < 0 && scrollY + dy < 0){dy = -scrollY;Log.i("test", "已經到達頂端,下拉多少,就往上滾動多少scrollY="+scrollY);}// 已經到達底部,上拉多少,就往下滾動多少if (dy > 0 && scrollY + dy > getHeight() - mScreenHeight){dy = getHeight() - mScreenHeight - scrollY;Log.i("test", "已經到達頂端,下拉多少,就往上滾動多少scrollY=="+scrollY);}Log.i("test", "dy="+dy+",scrollY"+scrollY);scrollBy(0, dy);mLastY = y;break;case MotionEvent.ACTION_UP:mScrollEnd = getScrollY();int dScrollY = mScrollEnd - mScrollStart;if (wantScrollToNext())// 往上滑動{if (shouldScrollToNext()){mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - dScrollY);} else{mScroller.startScroll(0, getScrollY(), 0, -dScrollY);}}if (wantScrollToPre())// 往下滑動{if (shouldScrollToPre()){mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight - dScrollY);} else{mScroller.startScroll(0, getScrollY(), 0, -dScrollY);}}isScrolling = true;postInvalidate();recycleVelocity();break;}return true;}/*** 根據滾動距離判斷是否能夠滾動到下一頁* * @return*/private boolean shouldScrollToNext(){return mScrollEnd - mScrollStart > mScreenHeight / 2 || Math.abs(getVelocity()) > 600;}/*** 根據用戶滑動,判斷用戶的意圖是否是滾動到下一頁* * @return*/private boolean wantScrollToNext(){return mScrollEnd > mScrollStart;}/*** 根據滾動距離判斷是否能夠滾動到上一頁* * @return*/private boolean shouldScrollToPre(){return -mScrollEnd + mScrollStart > mScreenHeight / 2 || Math.abs(getVelocity()) > 600;}/*** 根據用戶滑動,判斷用戶的意圖是否是滾動到上一頁* * @return*/private boolean wantScrollToPre(){return mScrollEnd < mScrollStart;}@Overridepublic void computeScroll(){super.computeScroll();if (mScroller.computeScrollOffset()){scrollTo(0, mScroller.getCurrY());postInvalidate();} else{int position = getScrollY() / mScreenHeight;Log.e("xxx", position + "," + currentPage);if (position != currentPage){if (mOnPageChangeListener != null){currentPage = position;mOnPageChangeListener.onPageChange(currentPage);}}isScrolling = false;}}/*** 獲取y方向的加速度* * @return*/private int getVelocity(){mVelocityTracker.computeCurrentVelocity(1000);return (int) mVelocityTracker.getYVelocity();}/*** 釋放資源*/private void recycleVelocity(){if (mVelocityTracker != null){mVelocityTracker.recycle();mVelocityTracker = null;}}/*** 初始化加速度檢測器* * @param event*/private void obtainVelocity(MotionEvent event){if (mVelocityTracker == null){mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.addMovement(event);}/*** 設置回調接口* * @param onPageChangeListener*/public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener){mOnPageChangeListener = onPageChangeListener;}/*** 回調接口* * @author zhy* */public interface OnPageChangeListener{void onPageChange(int currentPage);} }釋還是相當詳細的,我簡單描述一下,Action_down時獲得當前的scrollY,然后Action_move時,根據移動的距離不斷scrollby就行了,當前處理了一下邊界判斷,在Action_up中再次獲得scrollY,兩個的scrollY進行對比,然后根據移動的距離與方向決定最后的動作
MainActivity
package com.example.verticallinearlayout;import android.app.Activity; import android.os.Bundle; import android.widget.Toast;import com.example.verticallinearlayout.VerticalLinearLayout.OnPageChangeListener;public class MainActivity extends Activity {private VerticalLinearLayout mMianLayout;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mMianLayout = (VerticalLinearLayout) findViewById(R.id.id_main_ly);mMianLayout.setOnPageChangeListener(new OnPageChangeListener(){@Overridepublic void onPageChange(int currentPage){ // mMianLayout.getChildAt(currentPage);Toast.makeText(MainActivity.this, "第"+(currentPage+1)+"頁", Toast.LENGTH_SHORT).show();}});}}為了提供可擴展性,還是定義了回調接口,完全可以把這個當成一個垂直的ViewPager使用。
總結下:
Scroller這個輔助類還是相當好用的,原理我簡單說一下:每次滾動時,讓Scroller進行滾動,然后調用postInvalidate方法,這個方法會引發調用onDraw方法,onDraw方法中會去調用computeScroll方法,然后我們在computScroll中判斷,Scroller的滾動是否結束,沒有的話,把當前的View滾動到現在Scroller的位置,然后繼續調用postInvalidate,這樣一個循環的過程。
畫張圖方便大家理解,ps:沒找到什么好的畫圖工具,那rose隨便畫了,莫計較。
源碼
源碼點擊此處下載
完成
總結
以上是生活随笔為你收集整理的Andoird自定义ViewGroup实现竖向引导界面的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python刷题+leetcode(第一
- 下一篇: comparing ORB and AK