一个侧屏滑动操作的实例(仿遇见)之三:代码分析
首先看一下主activity:
package grimbo.android.demo.slidingmenu;import android.content.Context;import android.os.Handler;import android.util.AttributeSet;import android.util.Log;import android.view.GestureDetector;import android.view.GestureDetector.SimpleOnGestureListener;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewGroup;import android.view.GestureDetector.OnGestureListener;import android.view.ViewTreeObserver.OnGlobalLayoutListener;import android.widget.HorizontalScrollView;import android.widget.Scroller;public class MyHorizontalScrollView extends HorizontalScrollView {private final String tag = "MyHorizontalScrollView";private MyHorizontalScrollView me;//当前控件private View leftMenu;//左边菜单private View rightMenu;//右边菜单private boolean leftMenuOut = false;//左边菜单状态private boolean rightMenuOut = false;//左边菜单状态private final int ENLARGE_WIDTH = 20;//扩展宽度 public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public MyHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public MyHorizontalScrollView(Context context) { super(context); init(context); } void init(Context context) { // remove the fading as the HSV looks better without it //setHorizontalFadingEdgeEnabled(true); //setVerticalFadingEdgeEnabled(true); me = this; me.setVisibility(View.INVISIBLE); } public void initViews(View[] children, SizeCallback sizeCallback,View leftMenu,View rightMenu) { this.leftMenu = leftMenu; this.rightMenu = rightMenu; ViewGroup parent = (ViewGroup) getChildAt(0); // Add all the children, but add them invisible so that the layouts are calculated, but you can't see the Views for (int i = 0; i < children.length; i++) { children[i].setVisibility(View.INVISIBLE); parent.addView(children[i]); } // Add a layout listener to this HSV // This listener is responsible for arranging the child views. OnGlobalLayoutListener listener = new MyOnGlobalLayoutListener(parent, children, sizeCallback); getViewTreeObserver().addOnGlobalLayoutListener(listener); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // Do not allow touch events. return false; } class MyOnGlobalLayoutListener implements OnGlobalLayoutListener { ViewGroup parent; View[] children; int scrollToViewPos = 0; SizeCallback sizeCallback; public MyOnGlobalLayoutListener(ViewGroup parent, View[] children, SizeCallback sizeCallback) { this.parent = parent; this.children = children; this.sizeCallback = sizeCallback; } @Override public void onGlobalLayout() { me.getViewTreeObserver().removeGlobalOnLayoutListener(this); sizeCallback.onGlobalLayout(); parent.removeViewsInLayout(0, children.length); final int w = me.getMeasuredWidth(); final int h = me.getMeasuredHeight(); int[] dims = new int[2]; scrollToViewPos = 0; for (int i = 0; i < children.length; i++) { sizeCallback.getViewSize(i, w, h, dims); children[i].setVisibility(View.VISIBLE); parent.addView(children[i], dims[0], dims[1]); if (i == 0) { scrollToViewPos += dims[0]; } Log.d(tag, children[i]+": w=" + dims[0] + ", h=" + dims[1]); Log.d(tag, "scrollToViewIdx:"+0+",scrollToViewPos:"+scrollToViewPos); } new Handler().post(new Runnable() { @Override public void run() { me.scrollBy(scrollToViewPos,0); //因为这些控件默认都为隐藏,控件加载完成后,设置成显示 me.setVisibility(View.VISIBLE); leftMenu.setVisibility(View.VISIBLE); rightMenu.setVisibility(View.VISIBLE); } }); } } public void clickLeftButton(int leftButtonWidth){rightMenu.setVisibility(View.GONE);leftMenu.setVisibility(View.VISIBLE); int menuWidth = leftMenu.getMeasuredWidth()-(leftButtonWidth+ENLARGE_WIDTH); System.out.println("leftmenuWidth:"+menuWidth); if (!leftMenuOut) { int left = 0; me.smoothScrollTo(left, 0); } else { int left = menuWidth; me.smoothScrollTo(left, 0); } leftMenuOut = !leftMenuOut; } public void clickRightButton(int rightButtonWidth){leftMenu.setVisibility(View.GONE);rightMenu.setVisibility(View.VISIBLE);int menuWidth = rightMenu.getMeasuredWidth() - (rightButtonWidth+ENLARGE_WIDTH); if (!rightMenuOut) { int right = menuWidth + me.getMeasuredWidth(); System.out.println("rightmenuWidth:"+right); me.smoothScrollTo(right, 0); } else { int right = menuWidth; System.out.println("rightmenuWidth:"+right); me.smoothScrollTo(right, 0); } rightMenuOut = !rightMenuOut; } @Overridepublic boolean onTouchEvent(MotionEvent ev) { return false;} public interface SizeCallback { public void onGlobalLayout(); public void getViewSize(int idx, int w, int h, int[] dims); }}initViews:把传入的view加入第0个viewgroup,也就是xml中配置的LinearLayout中,并把一个MyOnGlobalLayoutListener对象设置为layout变化的观察者,initViews中放入的view只是占了个位置,后面的onGlobalLayout中会重新给这些view分配高和宽并加到LinearLayout中,但是在这之前需要预先放上去以得到某些控件的size(sizeCallback.onGlobalLayout()中),所以需要在这先加一次
onGlobalLayout:作为观察者,会在view的layout发生发生改变时自动调用此方法,由于只需要调用一次,所以方法里第一句就是调用removeGlobalOnLayoutListener,这个方法的主要功能就是把需要加入layout的views按照计算的宽度并加上去,然后调用me.scrollBy(scrollToViewPos,0);使加上去的view偏移,让tab01这个view偏移到屏幕可视范围中
clickLeftButton,clickRightButton:点击左边和右边的按钮时,控制MyHorizontalScrollView自身移动,显示出侧面相应的功能菜单,注意在移动之前,最左侧和最右侧是屏幕外的leftview和rightview,所以:
int left = 0;
me.smoothScrollTo(left, 0);
是把leftview移进来,中间的tab01向右移
完整源码下载地址:
http://download.csdn.net/detail/lamp_zy/4494989