一个侧屏滑动操作的实例(仿遇见)之三:代码分析


首先看一下主activity:

package grimbo.android.demo.slidingmenu;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
    private MyHorizontalScrollView scrollView;
    private View leftMenu;
    private View rightMenu;
    
    private View tab01;
    private Button leftButton;
    private Button rightButton;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        LayoutInflater inflater = LayoutInflater.from(this);
        setContentView(inflater.inflate(R.layout.main, null));

        scrollView = (MyHorizontalScrollView) findViewById(R.id.myScrollView);
        leftMenu = findViewById(R.id.leftmenu);
        rightMenu = findViewById(R.id.rightmenu);
        
        tab01 = inflater.inflate(R.layout.tab01, null);
        leftButton = (Button) tab01.findViewById(R.id.leftButton);
        rightButton = (Button)tab01.findViewById(R.id.rightButton);
        
        leftButton.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				scrollView.clickLeftButton(leftButton.getMeasuredWidth());
			}
		});
        
        rightButton.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				scrollView.clickRightButton(rightButton.getMeasuredWidth());
			}
		});
        

        View leftView = new View(this);//左边透明视图
        View rightView = new View(this);//右边透明视图
        leftView.setBackgroundColor(Color.TRANSPARENT);
        rightView.setBackgroundColor(Color.TRANSPARENT);
        final View[] children = new View[] {leftView, tab01,rightView };
        //初始化滚动布局
        scrollView.initViews(children, new SizeCallbackForMenu(leftButton),leftMenu,rightMenu);        
    }
}

其中tab01是一个由布局文件tab01.xml定义的view,放置“左边”和“右边”两个按钮

View leftView = new View(this);//左边透明视图
View rightView = new View(this);//右边透明视图
leftView.setBackgroundColor(Color.TRANSPARENT);
rightView.setBackgroundColor(Color.TRANSPARENT);

四句定义两个透明视图,透明视图就是只占用空间,不遮挡放置在其下面的视图

scrollView.initViews把两个透明视图和一个中间的tab视图放入HorizontalScrollView 的LinearLayout里,LinearLayout是横向布局,这样tab移到屏幕可视范围的时候就遮住了底下的leftmenu和rightmenu,当两侧透明视图移入屏幕可视范围的时候,底下的leftmenu或rightmenu就显现出来了,以此实现侧滑效果


然后看一下自定义的滑动类MyHorizontalScrollView

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;
    }
    
    

    @Override
	public 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

你可能感兴趣的:(代码)