Android自己定义组件系列【4】——自己定义ViewGroup实现双側滑动
在上一篇文章《Android自己定義組件系列【3】——自己定義ViewGroup實現側滑》中實現了仿Facebook和人人網的側滑效果,這一篇我們將接著上一篇來實現雙面滑動的效果。
1、布局示意圖:
2、核心代碼
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec); //獲取MyScrollView的寬度mHeight = MeasureSpec.getSize(heightMeasureSpec); //獲取MyScrollView的高度if(!isLocked){initX = getScrollX();isLocked = true;}}在該方法中獲取到初始的視圖坐標偏移量getScrollX()
@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:System.out.println("ACTION_DOWN");mDownX = x; //記錄按下時的x坐標break;case MotionEvent.ACTION_UP:System.out.println("ACTION_UP");int dis = (int) (x - mDownX); //滑動的距離if(Math.abs(dis) > (mWidth * mMenuWeight / 2)){if(dis > 0){ //假設>0則是向右滑動toRightMove();}else{ //假設<0則是向左滑動toLeftMove();}}break;default:break;}return true;}監聽函數記錄下按下和移動的屏幕坐標。求差計算出移動距離,假設這個距離大于閥值 (mWidth * mMenuWeight / 2)則滑動
public void toRightMove(){System.out.println("maxRight = " + maxRight);System.out.println("X = " + getScrollX());if(getScrollX() >= initX){int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);if(mListener != null){mListener.onChanged();}invalidate();}}假設是向右滑動則。假設當前是初始位置(centerView在中間)則能夠向右滑動(getScrollX == initX),或者當前左邊View能夠看見,則能夠向右滑動將centerView移動到中間(getScrollX > initX).同理有向左滑動的方法。
public void toLeftMove(){System.out.println("maxLeft = " + maxLeft);System.out.println("X = " + getScrollX());if(getScrollX() <= initX){int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, dx, 0, 500);if(mListener != null){mListener.onChanged();}invalidate();}}3、所有代碼
MyScrollView.java
package com.example.testscrollto;import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.Scroller;public class MyScrollView extends LinearLayout{private Context mContext;private int mWidth;private int mHeight;private float mMenuWeight = 3.0f / 5; //菜單界面比例private View mMenuView; //菜單界面private View mPriView; //內容界面private View mRightView; //右邊界面private int maxLeft;private int maxRight;private int initX;private boolean isLocked = false;private Scroller mScroller;private OnMenuChangedListener mListener;public MyScrollView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;mScroller = new Scroller(mContext);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);mMenuView.layout(-(int)(mWidth * mMenuWeight), 0, 0, mHeight);mPriView.layout(0, 0, mWidth, mHeight);mRightView.layout(mWidth, 0, mWidth + (int)(mWidth * mMenuWeight), mHeight);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec); //獲取MyScrollView的寬度mHeight = MeasureSpec.getSize(heightMeasureSpec); //獲取MyScrollView的高度if(!isLocked){initX = getScrollX();isLocked = true;}}/**設置右滑的菜單View*/public void setMenu(View menu){mMenuView = menu;addView(mMenuView);}/*** 設置主界面View*/public void setPrimary(View primary){mPriView = primary;addView(mPriView);}public void setRightView(View rightview){mRightView = rightview;addView(mRightView);}private float mDownX;@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:System.out.println("ACTION_DOWN");mDownX = x; //記錄按下時的x坐標break;case MotionEvent.ACTION_UP:System.out.println("ACTION_UP");int dis = (int) (x - mDownX); //滑動的距離if(Math.abs(dis) > (mWidth * mMenuWeight / 2)){if(dis > 0){ //假設>0則是向右滑動toRightMove();}else{ //假設<0則是向左滑動toLeftMove();}}break;default:break;}return true;}@Overridepublic void computeScroll() {super.computeScroll();if(mScroller.computeScrollOffset()){scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}}public void toRightMove(){System.out.println("maxRight = " + maxRight);System.out.println("X = " + getScrollX());if(getScrollX() >= initX){int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);if(mListener != null){mListener.onChanged();}invalidate();}}public void toLeftMove(){System.out.println("maxLeft = " + maxLeft);System.out.println("X = " + getScrollX());if(getScrollX() <= initX){int dx = (int)(mWidth * mMenuWeight);mScroller.startScroll(getScrollX(), 0, dx, 0, 500);if(mListener != null){mListener.onChanged();}invalidate();}}public interface OnMenuChangedListener{public void onChanged();} public void setOnMenuChangedListener(OnMenuChangedListener listener){mListener = listener;} } MainActivity.java
package com.example.testscrollto;import android.app.Activity; import android.os.Bundle; import android.view.View;import com.example.testscrollto.MyScrollView.OnMenuChangedListener;public class MainActivity extends Activity {private MyScrollView mScrollView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mScrollView = (MyScrollView)findViewById(R.id.rightscrollview);final View menu = getLayoutInflater().inflate(R.layout.rightscrollview_menu, null);final View primary = getLayoutInflater().inflate(R.layout.rightscrollview_primary, null);final View rightview = getLayoutInflater().inflate(R.layout.rightscrollview_right_menu, null);mScrollView.setMenu(menu);mScrollView.setPrimary(primary);mScrollView.setRightView(rightview);mScrollView.setOnMenuChangedListener(new OnMenuChangedListener() {@Overridepublic void onChanged() {System.out.println("窗體切換了一次");}});} }activity_main.xml<?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" ><com.example.testscrollto.MyScrollViewandroid:id="@+id/rightscrollview"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>其余三個視圖界面無限制。能夠自由定義,這里就不貼出來了。
4、執行效果:
源碼下載:http://download.csdn.net/detail/lxq_xsyu/7232701
這樣就能夠實現左右滑動了,沒有不論什么bug嗎?
事實上這樣看似是沒有什么問題了,上面用于推斷界面位置的代碼在邏輯上看似是對的,可是在實際的應用中偶爾會出現錯亂。
以下我們用第二種方式解決:
package com.example.jaohangui.view;import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; import android.widget.Scroller;public class MyScrollLeftRightView extends LinearLayout{private Scroller mScroller;private View mLeftView; //坐標界面private View mMainView; //中間主界面private View mRightView; //右邊界面private float mMeasureWight = 3.0f / 5; //菜單界面比例private int mWidth; private int mHeight;private boolean isLocked = false;private boolean isToLeft = false;private static int CENTER_PAGE = 1;private static int LEFT_PAGE = 0;private static int RIGHT_PAGE = 2;private int currentPage = CENTER_PAGE;public MyScrollLeftRightView(Context context, AttributeSet attrs) {super(context, attrs);mScroller = new Scroller(context);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);mLeftView.layout(-(int)(mWidth * mMeasureWight), 0, 0, mHeight);mMainView.layout(0, 0, mWidth, mHeight);mRightView.layout(mWidth, 0, mWidth + (int)(mWidth * mMeasureWight), mHeight);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);mHeight = MeasureSpec.getSize(heightMeasureSpec);}/*** 加入左邊界面內容* @param view*/public void setLeftView(View view){mLeftView = view;addView(mLeftView);}/*** 加入主界面內容* @param view*/public void setMainView(View view){mMainView = view;addView(mMainView);}/*** 加入右邊界面內容* @param view*/public void setRightView(View view){mRightView = view;addView(mRightView);}private float mDownX;@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mDownX = x;break;case MotionEvent.ACTION_UP:int dis = (int)(x - mDownX); //滑動的距離if(Math.abs(dis) > (mWidth * mMeasureWight / 3)){if(dis > 0){toRightMove();}else{toLeftMove();}}break;default:break;}return true;}@Overridepublic void computeScroll() {super.computeScroll();if(mScroller.computeScrollOffset()){isLocked = true;scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}else{if(currentPage == CENTER_PAGE){if(isToLeft){currentPage = RIGHT_PAGE;}else{currentPage = LEFT_PAGE;}}else{currentPage = CENTER_PAGE;}isLocked = false;}}public void toRightMove(){if(currentPage == LEFT_PAGE || isLocked){return;}int dx = (int)(mWidth * mMeasureWight);mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);invalidate();isToLeft = false;}public void toLeftMove(){if(currentPage == RIGHT_PAGE || isLocked){return;}System.out.println("ok");int dx = (int)(mWidth * mMeasureWight);mScroller.startScroll(getScrollX(), 0, dx, 0, 500);invalidate();isToLeft = true;} }上面使用了兩個用來推斷的變量和一個鎖定狀態(不讓進入toLeftMove和toRightMove)的變量。
1、在進入toLeftMove或者toRightMove方法的時候首先會推斷是否isLocked為true,假設為true則說明當前是正在滑動狀態,不能夠執行這兩個方法。假設不這樣去控制。在界面正在滑動的時候上面的currentPage就會發生錯亂。
2、將要滑動之前告訴computeScroll()方法,是從toLeftMove和toRightMove的那個方法中出來的(使用isToLeft)。
3、最后推斷Scroller是否已經停止滑動(移動),假設停止則改變當前頁面的狀態(currentPage的值)
有的時候我們盡管實現了一個功能或者某個邏輯,而怎樣才干使這段代碼更加健壯和有效更值得我們去認真思考。
。。
總結
以上是生活随笔為你收集整理的Android自己定义组件系列【4】——自己定义ViewGroup实现双側滑动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java/Android引用类型及其使用
- 下一篇: CORS解决WebApi跨域问题(转)