Android 自訂控制項 GuideView 引導介面

來源:互聯網
上載者:User

標籤:android   guidview   引導介面   

最近看了hyman的部落格:http://blog.csdn.net/lmj623565791/article/details/23692439 ,由於個人技術還比較薄弱,就在這個自訂控制項的基礎上做了個拓展,支援水平和垂直的

下面是主要代碼;


    GuideView:

    

import android.annotation.SuppressLint;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Point;import android.graphics.PointF;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;import android.widget.Toast;@SuppressLint("ClickableViewAccessibility")public class GuideView extends ViewGroup {/** *  <attr name="orientation"> <enum name="horizontal" value="1" /> <enum * name="vertical" value="2" /> </attr> **//** 滑動方向 */private int mOrientation = 0;/** 水平方向 */private int mHorientation = 0;/** 垂直方向 */private int mVertical = 1;/** 螢幕寬度 */private int mScreenWidth;/** 螢幕高度 */private int mScreenHeight;/** 滑動狀態 */private boolean isScrolling;/** 滑動輔助類 */private Scroller mScroller;/** 記錄當前的x/y的值 */private PointF mPointF;/** 記錄上一次的x、y值 */private PointF mLastPointF;/** Scroller 對應的開始座標 */private Point mScrollStartPoint;/** Scroller 對應的結束座標 */private Point mScrollStopPoint;/** 記錄滑動的距離 */private PointF mDistancePointF;/**ScrollXY 的差值*/private Point mDistanceScrollPoint;/** 加速度檢測 */private VelocityTracker mVelocityTracker;/**切換畫面時的回呼函數*/private OnPageChangeListener mOnPageChangeListener;/** * 記錄當前頁 */private int currentPage = 0;public GuideView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);// TODO Auto-generated constructor stub// 擷取自訂屬性TypedArray mTypeArray = context.obtainStyledAttributes(attrs, R.styleable.GuideView_orientation);mOrientation = mTypeArray.getInteger(R.styleable.GuideView_orientation_orientation, mOrientation);mTypeArray.recycle();// 擷取螢幕寬高initialScreen(context);mScroller = new Scroller(context);mPointF = new PointF();mLastPointF = new PointF();mScrollStartPoint = new Point();mScrollStopPoint = new Point();mDistancePointF = new PointF();mDistanceScrollPoint=new Point();}public GuideView(Context context, AttributeSet attrs) {this(context, attrs, 1);// TODO Auto-generated constructor stub}public GuideView(Context context) {this(context, null);// TODO Auto-generated constructor stub}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);// 擷取子布局,重新測量子布局寬高int count = getChildCount();for (int i = 0; i < count; i++) {measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubif (changed) {// 重新測量layout的位置MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();int childCount = getChildCount();if (mOrientation == mHorientation) {params.width = mScreenWidth * getChildCount();setLayoutParams(params);for (int i = 0; i < childCount; i++) {View view = getChildAt(i);if (view.getVisibility() != View.GONE) {view.layout(i * mScreenWidth, t, i * mScreenWidth+ mScreenWidth, b);}}} else if (mOrientation == mVertical) {params.height = mScreenHeight * getChildCount();setLayoutParams(params);for (int i = 0; i < childCount; i++) {View view = getChildAt(i);// view 沒有隱藏掉,就重新置放if (view.getVisibility() != View.GONE) {view.layout(l, i * mScreenHeight, r, i * mScreenHeight+ mScreenHeight);}}}}}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stub// 先進行事件判斷攔截if(currentPage==getChildCount()-1){Toast.makeText(getContext(), "finish", Toast.LENGTH_SHORT).show();return super.onTouchEvent(event);}if (isScrolling) return super.onTouchEvent(event);mPointF.x = event.getX();mPointF.y = event.getY();// 初始化加速度檢測器initialVelocity(event);if (event.getAction() == MotionEvent.ACTION_DOWN) {// 當使用者觸摸時記錄下座標資訊Log.i("info"," *******mPoint value****"+"x:"+mPointF.x+"y:"+mPointF.y);getStartScrollXY();mLastPointF.x = mPointF.x;mLastPointF.y = mPointF.y;} else if (event.getAction() == MotionEvent.ACTION_MOVE) {Log.i("info"," *******mLastPoint value****"+"x:"+mLastPointF.x+"y:"+mLastPointF.y);Log.i("info"," *******mPoint value****"+"x:"+mPointF.x+"y:"+mPointF.y);Log.i("info"," *******************************************");Log.i("info"," *******************************************");/** * Stops the animation. Contrary to * {@link #forceFinished(boolean)}, aborting the animating cause * the scroller to move to the final x and y position 源碼說明: * mScroller.abortAnimation() 如果滑動還沒有結束,那麼就終止滑動。 *  * @see #forceFinished(boolean) */if (!mScroller.isFinished()) {mScroller.abortAnimation();}mDistancePointF.x = mLastPointF.x - mPointF.x;mDistancePointF.y = mLastPointF.y - mPointF.y;Log.i("info"," *******mDistancePointF value ******"+"dx: "+mDistancePointF.x+" dy: "+mDistancePointF.y);getStopScrollXY();// 先判斷滑動的方向確定滑動的距離 scrollBy(x,y)// 1.y軸---向上滑動--下一個視圖// 2.y軸---向下滑動--上一個視圖// 3.x軸---向左滑動--下一個視圖// 4.x軸---向右滑動--上一個視圖/** * 320*480 -8 mlasty=-10 currenty=-2 * distance=mlasty-currenty=-8《0 scrolly+distance<0? *  * 條件都滿足時,確定視圖向上滑動,載入 下一個視圖 *  * 重新定義distanceY的值以便於ScrollBy(x,y)調用 *  * 補充說明: * getScrollX()說明:=手機螢幕顯示地區左上方x座標減去MultiViewGroup視圖左上方x座標=320 *  * getScrollY()說明:=手機螢幕顯示地區左上方y座標減去MultiViewGroup視圖左上方y座標=0( * 因為子視圖的高度和手機螢幕高度一樣) *  *  **/if (mOrientation == mHorientation) {if (mDistancePointF.x > 0&& mScrollStopPoint.x + mDistancePointF.x > getWidth()-mScreenWidth) {mDistancePointF.x = getWidth() - mScreenWidth -mScrollStopPoint.x;} else if (mDistancePointF.x < 0&& mScrollStopPoint.x + mDistancePointF.x < 0) {mDistancePointF.x = - mScrollStopPoint.x;}scrollBy((int) mDistancePointF.x, 0);} else if (mOrientation == mVertical) {if (mDistancePointF.y < 0&& mScrollStopPoint.y + mDistancePointF.y < 0) {mDistancePointF.y = -mScrollStopPoint.y;}if (mDistancePointF.y > 0&& mScrollStopPoint.y + mDistancePointF.y > getHeight()- mScreenHeight) {mDistancePointF.y = getHeight() - mScreenHeight- mScrollStopPoint.y;}scrollBy(0, (int) mDistancePointF.y);}mLastPointF.x = mPointF.x;mLastPointF.y = mPointF.y;} else if (event.getAction() == MotionEvent.ACTION_UP) {getStopScrollXY();getDistanceScrollXY();//比較滑動方向趨勢//判斷是上滑動還是下滑動if(checkDirection()){//上滑動《載入更多》if(isScrollToNext()){//能滑動到下一頁if(mOrientation==mHorientation){mScroller.startScroll(getScrollX(), 0,mScreenWidth - mDistanceScrollPoint.x,0);}else if (mOrientation==mVertical){mScroller.startScroll(0, getScrollY(), 0, mScreenHeight- mDistanceScrollPoint.y);}}else{//不能滑動到下一頁if(mOrientation==mHorientation){mScroller.startScroll(getScrollX(), 0,-mDistanceScrollPoint.x,0);}else if (mOrientation==mVertical){mScroller.startScroll(0, getScrollY(), 0, -mDistanceScrollPoint.y);}}}else{//《下滑動,重新整理》if(isScrollToprivew()){//能滑動到上一頁if(mOrientation==mHorientation){mScroller.startScroll( getScrollX(), 0,-mScreenWidth - mDistanceScrollPoint.x,0);}else if (mOrientation==mVertical){mScroller.startScroll(0, getScrollY(), 0,-mScreenHeight - mDistanceScrollPoint.y);}}else{//不能滑動到上一頁if(mOrientation==mHorientation){mScroller.startScroll(getScrollX(),0, -mDistanceScrollPoint.x, 0);}else if (mOrientation==mVertical){mScroller.startScroll(0, getScrollY(), 0, -mDistanceScrollPoint.y);}}}isScrolling = true;postInvalidate();recycleVelocity();}return true;}/** * Called by a parent to request that a child update its values for mScrollX * and mScrollY if necessary. This will typically be done if the child is * animating a scroll using a {@link android.widget.Scroller Scroller} * object. *  * 為了易於控制滑屏控制,Android架構提供了 computeScroll()方法去控制這個流程。在繪製View時,會在draw()程序呼叫該 * 方法。因此, 再配合使用Scroller執行個體,我們就可以獲得當前應該的位移座標,手動使View/ViewGroup位移至該處。 * computeScroll()方法原型如下,該方法位於ViewGroup.java類中    */@Overridepublic void computeScroll() {// TODO Auto-generated method stubsuper.computeScroll();if (mOrientation== mVertical) {if (mScroller.computeScrollOffset()) {scrollTo(0, mScroller.getCurrY());postInvalidate();} else {int position = getScrollY() / mScreenHeight;if (position != currentPage) {if (mOnPageChangeListener != null) {currentPage = position;mOnPageChangeListener.onPageChange(currentPage);}}}} else if (mOrientation== mHorientation) {if (mScroller.computeScrollOffset()) {scrollTo(mScroller.getCurrX(), 0);postInvalidate();} else {int position = getScrollX() / mScreenWidth;if (position != currentPage) {if (mOnPageChangeListener != null) {currentPage = position;mOnPageChangeListener.onPageChange(currentPage);}}}}isScrolling = false;}/************************************ Method *********************************************//** * 擷取螢幕寬高 */public void initialScreen(Context context) {WindowManager mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();mWindowManager.getDefaultDisplay().getMetrics(outMetrics);mScreenWidth = outMetrics.widthPixels;mScreenHeight = outMetrics.heightPixels;}/** * 初始化加速度檢測器 *  * @param event */private void initialVelocity(MotionEvent event) {if (mVelocityTracker == null) {mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.addMovement(event);}/** * 初始化scrollX scrollY */private void getStartScrollXY(){mScrollStartPoint.x = getScrollX();mScrollStartPoint.y = getScrollY();}/** * 停止滑動後的ScrollX ScrollY */private void getStopScrollXY(){mScrollStopPoint.x = getScrollX();mScrollStopPoint.y = getScrollY();}/** * 比較滑動的ScrollX ScrollY差值 */private void getDistanceScrollXY(){mDistanceScrollPoint.x = mScrollStopPoint.x-mScrollStartPoint.x;mDistanceScrollPoint.y = mScrollStopPoint.y-mScrollStartPoint.y;}/** * 檢查滑動方向 * @return  true 載入更多  false 重新整理 */public boolean checkDirection(){boolean mDirection =false;if (mOrientation == mVertical) {mDirection = mDistanceScrollPoint.y > 0 ? true : false;} else if (mOrientation== mHorientation) {mDirection = - mDistanceScrollPoint.x < 0 ? true : false;}return mDirection;}/** * 根據滑動距離判斷 是否能夠滑動到下一屏 *  載入跟多 * @return */private boolean isScrollToNext() {boolean isScrollTo = false;if (mOrientation == mVertical) {isScrollTo = mDistanceScrollPoint.y > mScreenHeight / 2|| Math.abs(getVelocity()) > 600;} else if (mOrientation == mHorientation) {isScrollTo = mDistanceScrollPoint.x > mScreenWidth / 2|| Math.abs(getVelocitx()) > 600;}return isScrollTo;}/** * 根據滑動距離判斷 是否能夠滑動到上一屏 * 重新整理 * @return */private boolean isScrollToprivew() {boolean isScrollTo = false;if (mOrientation == mVertical) {isScrollTo = -mDistanceScrollPoint.y > mScreenHeight / 2|| Math.abs(getVelocity()) > 600;} else if (mOrientation == mHorientation) {isScrollTo = -mDistanceScrollPoint.x > mScreenWidth / 2|| Math.abs(getVelocitx()) > 600;}return isScrollTo;}/** * 擷取x方向的加速度 *  * @return */private int getVelocitx() {mVelocityTracker.computeCurrentVelocity(1000);int velocitx = (int) mVelocityTracker.getXVelocity(1000);velocitx = (int) mVelocityTracker.getXVelocity(1000);return velocitx;}/** * 擷取y方向的加速度 *  * @return */private int getVelocity() {mVelocityTracker.computeCurrentVelocity(1000);int velocity = (int) mVelocityTracker.getYVelocity(1000);velocity = (int) mVelocityTracker.getYVelocity(1000);return velocity;}/** * 釋放資源 */private void recycleVelocity() {if (mVelocityTracker != null) {mVelocityTracker.recycle();mVelocityTracker = null;}}/** * 設定回調介面 *  * @param onPageChangeListener */public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener) {mOnPageChangeListener = onPageChangeListener;}/** * 回調介面 *  * @author zhy *  */public interface OnPageChangeListener {void onPageChange(int currentPage);}}

    attrs:

    

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="GuideView_orientation">        <attr name="orientation">            <enum name="Horientation" value="0" />            <enum name="Vertical" value="1" />        </attr>    </declare-styleable></resources>

源碼:  http://download.csdn.net/detail/anddroid_lanyan/8660753

在項目還存在遺留問題:(取消page的攔截事件)當我把背景色改成白色時,水平布局,左右滑動反覆,會出現白邊,還沒搞明白具體問題,誰若是知道麻煩告知。

改完這個自訂控制項後,我發現一件事,只要你願意堅持去做一件事,就一定會有所收穫。

Android 自訂控制項 GuideView 引導介面

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.