自定义ViewGroup之QQ5.0侧滑效果实现

转载请注明出处:http://blog.csdn.net/wei_chong_chong/article/details/50839113

谢谢!

以前写过一个QQ侧滑的博客,那个是一般侧滑效果,今天来做一个更牛逼的效果。

首先看一下,

一般效果实现:

ViewGroup  Menu+Content

原理:

(自定义一个ViewGroup或LinearLayout或RelativeLayout,左边放一个Menu右边放一个Content),

监听onTouchEvent事件

MOVE:不断改变ViewGroup的leftMargin

UP;根据显示菜单的宽度,决定将其隐藏或者显示

1.Scroller

2.LeftMargin +Thread

见我的另外一篇文章:http://blog.csdn.net/wei_chong_chong/article/details/50807353

今天,用另一种方法实现:继承HorizontalScrollView


自定义ViewGroup(View)

1.onMeasure

决定内部View(子View)的宽和高,以及自己的宽和高

2.onLayout

决定子View的放置位置

3.onTouchEvent

判断手指的动作,按下,抬起等进而决定View的移动效果

更详细的自定义view请参考我的另外一篇博客http://blog.csdn.net/wei_chong_chong/article/details/50814617

没有使用自定义属性时默认调用两个参数的构造方法

整理一下思路:

首先构造方法中获得屏幕宽度,把单位转换为px

2.在onMeasuer()设置子View的宽和高

3.在onLayout()中隐藏菜单

4.在onTouchEvent()中up事件进行处理

现在已经基本上能实现滑动效果了

先把代码贴出来吧:

第一步:创建mMenu菜单布局left_menu.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:gravity="center"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="10dp" >

        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:src="@drawable/img_1" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="第一个item"
            android:textColor="#ffffff" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="10dp" >

        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:src="@drawable/img_2" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="第二个item"
            android:textColor="#ffffff" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="10dp" >

        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:src="@drawable/img_3" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="第三个item"
            android:textColor="#ffffff" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="10dp" >

        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:src="@drawable/img_4" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="第四个item"
            android:textColor="#ffffff" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="10dp" >

        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:src="@drawable/img_5" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="第五个item"
            android:textColor="#ffffff" />
    </LinearLayout>

</LinearLayout>

2.创建自定义布局:

public class SlidingMenu extends HorizontalScrollView{

	/**
	 * 未使用自定义属性时使用
	 * @param context
	 * @param attrs
	 * 
	 */
	//水平滚动条
	private LinearLayout mWapper;
	//菜单
	private ViewGroup mMenu;
	//内容区域
	private ViewGroup mContent;
	//屏幕宽度
	private int mScreenWidth;
	private int mMenuWidth;
	//dp
	private int mMenuRightPadding = 50;

	private boolean once;



	public SlidingMenu(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		//获取屏幕宽度
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(outMetrics);
		mScreenWidth = outMetrics.widthPixels;
		//把dp转换为px
		TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, 
				context.getResources().getDisplayMetrics());
	}
	/**
	 * 设置View的宽和高 设置自己的宽和高
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		/**
		 * 使用once标记使设置宽度的方法只调用一次就行了,没必要多次设置
		 */
		if(!once){
			mWapper = (LinearLayout) getChildAt(0);
			//LinearLayout中的第一个元素
			mMenu = (ViewGroup) mWapper.getChildAt(0);
			//LinearLayout中的第二个元素
			mContent = (ViewGroup) mWapper.getChildAt(1);
			//设置mMenu的宽度
			mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;
			//设置mContent的宽度
			mContent.getLayoutParams().width = mScreenWidth;
			once = true;
		}

		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
	/**
	 * 设置偏移量,将menu隐藏
	 */

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// TODO Auto-generated method stub
		super.onLayout(changed, l, t, r, b);
		//如果发生变化调用,设置偏移量,将menu隐藏
		if(changed){
			//this.scrollTo(x,y)this是滚动条,x为正值时滚动条向左移动,滚动条向右移动内容区域向左移动
			this.scrollTo(mMenuWidth, 0);//y轴不用移动0
		}

	}
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		int action = ev.getAction();
		//因为HorizontalScrollView能自己控制MOVE和Down的事件,即使不做任何处理,它也能把菜单划出来和隐藏,所以这里只需监听一下UP事件就行
		switch (action) {
		case MotionEvent.ACTION_UP:
			int scrollX	= getScrollX();//隐藏左边的宽度,在内容区域左侧多出来的部分(内容部分太大左侧未被屏幕完全显示出来,隐藏在屏幕左边的部分)
			if(scrollX >= mMenuWidth/2){
				this.smoothScrollTo(mMenuWidth, 0);
				//这里使用smoothScrollTo(x,y)方法使有个过渡,因为scrollTo(x,y)是瞬间完成的
			}else {
				//将内容区域完全显示
				this.smoothScrollTo(0, 0);
			}	
			return true;
		}
		return super.onTouchEvent(ev);
	}
}

3.在主布局中引用自定义控件


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/img_frame_background"
    tools:context="com.example.slidingmenu.MainActivity" >

    <com.example.slidingmenu.myview.SlidingMenu
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal" >

            <include layout="@layout/left_menu" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/qq" >
            </LinearLayout>
        </LinearLayout>
    </com.example.slidingmenu.myview.SlidingMenu>

</RelativeLayout>



下面自定义属性:允许用户设置菜单离屏幕右边的距离

1.书写xml文件定义属性values/attr.xml

2.在布局中使用

引入命名空间,hyman:名称可以随便写

 xmlns:hyman="http://schemas.android.com/apk/res/com.example.slidingmenu"

com.example.slidingmenu:这个是当前应用的包名,不是自定义View的包名,这个需要注意


下面我们再加入按钮,效果点击显示和关闭mMenu菜单

加入一个布尔类型的变量,标识当前的状态

//加入boolean类型的变量标识当前的状态(菜单是否打开)
private boolean isOpen;

在下面代码中修改状态

switch (action) {
		case MotionEvent.ACTION_UP:
			int scrollX	= getScrollX();//隐藏左边的宽度,在内容区域左侧多出来的部分(内容部分太大左侧未被屏幕完全显示出来,隐藏在屏幕左边的部分)
			if(scrollX >= mMenuWidth/2){
				this.smoothScrollTo(mMenuWidth, 0);
				//这里使用smoothScrollTo(x,y)方法使有个过渡,因为scrollTo(x,y)是瞬间完成的
				isOpen = false;//将状态设置为关闭状态
			}else {
				//将内容区域完全显示
				this.smoothScrollTo(0, 0);
				isOpen = true;//将状态设置为打开状态
			}	
			return true;
		}


添加方法

/**
	 * 打开菜单
	 */
	public void openMenu(){
		if(isOpen)return;
		this.smoothScrollTo(0, 0);
		isOpen = true;
	}
	public void closeMenu(){
		if(!isOpen)return;
		this.smoothScrollTo(mMenuWidth, 0);
		isOpen = false;
	}
	/**
	 * 切换菜单
	 */
	public void toggle(){
		if(isOpen){
			closeMenu();
		}else{
			openMenu();
		}
	}

修改后的的代码如下:

public class SlidingMenu extends HorizontalScrollView{

	/**
	 * 未使用自定义属性时使用
	 * @param context
	 * @param attrs
	 * 
	 */
	//水平滚动条
	private LinearLayout mWapper;
	//菜单
	private ViewGroup mMenu;
	//内容区域
	private ViewGroup mContent;
	//屏幕宽度
	private int mScreenWidth;
	private int mMenuWidth;
	//dp
	private int mMenuRightPadding = 50;

	private boolean once;

	//加入boolean类型的变量标识当前的状态(菜单是否打开)
	private boolean isOpen;


	/**
	 * 当使用了自定义的属性时,会调用此构造方法
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */

	public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		// TODO Auto-generated constructor stub
		//获取我们定义的属性
		TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.SlidingMenu, defStyle,0);
		int n = a.getIndexCount();//获得自定义属性的数量
		for (int i = 0; i < n; i++) {
			int attr = a.getIndex(i);//根据下标获得自定义属性
			switch (attr) {
			case R.styleable.SlidingMenu_rightPadding:

				mMenuRightPadding = a.getDimensionPixelSize(attr,
						(int)TypedValue.applyDimension(
								TypedValue.COMPLEX_UNIT_DIP, 50, 
								context.getResources().getDisplayMetrics()));//getDimensionPixelSize()第二个参数是默认值50dp
				break;

			}
		}
		a.recycle();
		//获取屏幕宽度
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(outMetrics);
		mScreenWidth = outMetrics.widthPixels;
		//把dp转换为px
		//		mMenuRightPadding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, 
		//				context.getResources().getDisplayMetrics());
	}
	/*
	 * 什么时候调用一个参数的构造方法:在代码里面new传一个上下文就行了
	 */
	public SlidingMenu(Context context) {
		this(context,null);
		// TODO Auto-generated constructor stub
	}
	public SlidingMenu(Context context, AttributeSet attrs) {

		this(context,attrs,0);
	}
	/**
	 * 设置View的宽和高 设置自己的宽和高
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		/**
		 * 使用once标记使设置宽度的方法只调用一次就行了,没必要多次设置
		 */
		if(!once){
			mWapper = (LinearLayout) getChildAt(0);
			//LinearLayout中的第一个元素
			mMenu = (ViewGroup) mWapper.getChildAt(0);
			//LinearLayout中的第二个元素
			mContent = (ViewGroup) mWapper.getChildAt(1);
			//设置mMenu的宽度
			mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;
			//设置mContent的宽度
			mContent.getLayoutParams().width = mScreenWidth;
			once = true;
		}

		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
	/**
	 * 设置偏移量,将menu隐藏
	 */

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// TODO Auto-generated method stub
		super.onLayout(changed, l, t, r, b);
		//如果发生变化调用,设置偏移量,将menu隐藏
		if(changed){
			//this.scrollTo(x,y)this是滚动条,x为正值时滚动条向左移动,滚动条向右移动内容区域向左移动
			this.scrollTo(mMenuWidth, 0);//y轴不用移动0
		}

	}
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		int action = ev.getAction();
		//因为HorizontalScrollView能自己控制MOVE和Down的事件,即使不做任何处理,它也能把菜单划出来和隐藏,所以这里只需监听一下UP事件就行
		switch (action) {
		case MotionEvent.ACTION_UP:
			int scrollX	= getScrollX();//隐藏左边的宽度,在内容区域左侧多出来的部分(内容部分太大左侧未被屏幕完全显示出来,隐藏在屏幕左边的部分)
			if(scrollX >= mMenuWidth/2){
				this.smoothScrollTo(mMenuWidth, 0);
				//这里使用smoothScrollTo(x,y)方法使有个过渡,因为scrollTo(x,y)是瞬间完成的
				isOpen = false;//将状态设置为关闭状态
			}else {
				//将内容区域完全显示
				this.smoothScrollTo(0, 0);
				isOpen = true;//将状态设置为打开状态
			}	
			return true;
		}
		return super.onTouchEvent(ev);
	}
	/**
	 * 打开菜单
	 */
	public void openMenu(){
		if(isOpen)return;
		this.smoothScrollTo(0, 0);
		isOpen = true;
	}
	public void closeMenu(){
		if(!isOpen)return;
		this.smoothScrollTo(mMenuWidth, 0);
		isOpen = false;
	}
	/**
	 * 切换菜单
	 */
	public void toggle(){
		if(isOpen){
			closeMenu();
		}else{
			openMenu();
		}
	}
}
另外在主界面中加入一个按钮

在MainActivity中添加按钮点击事件

这些我就不写了


侧滑菜单效果二:抽屉式侧滑:菜单仿佛在在内容区域以下

我们在拉之前,给菜单设置偏移量,向右偏移

      没拉时                         偏移量是   mMenu - 0         

我们拉出来100像素时,向右偏移量是mMenuWidth - 100;

      拉出来200时                   偏移是mMenuWidth - 200

实现偏移量 属性动画:TraslationX

getScrollX:mMenuWidth ~ 0

调用动画时机

实现方法:

HorizontalScrollView中有一个方法

其中第一个参数l就是getScrollx,变化值mMenu ~ 0,这里正好可以使用

/**
	 * 滚动条变化时的回调方法
	 * 参数1.就是getScrollX
	 * 参数2,3,4是变化的梯度
	 */

	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		// TODO Auto-generated method stub
		super.onScrollChanged(l, t, oldl, oldt);
		//调用属性动画,设置TransactionX

		ViewHelper.setTranslationX(mMenu, l);
	}

//调用属性动画,设置TransactionX

ViewHelper.setTranslationX(mMenu, l);

调用属性动画需要一个导入一个jar包,这个大家都知道吧,可以在我的资源文件中下载

现在我们实现与qq5.0效果还是有一些区别

1.内容区域1.0 ~ 0.7缩放效果

scale :1.0~0.0

0.7 + 0.3 * scale

2. 菜单偏移量需要修改


3.菜单的显示时有缩放,以及透明度变化

缩放:0.7 ~ 1.0

1.0 - scale * 0.3

透明度 :0.6 ~ 1.0

0.6 + 0.4 *(1 - scale)

实现代码:

	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		// TODO Auto-generated method stub
		super.onScrollChanged(l, t, oldl, oldt);

		/**
		 * 1.内容区域1.0 ~ 0.7缩放效果
			scale :1.0~0.0
			0.7 + 0.3 * scale
			2. 菜单偏移量需要修改

			3.菜单的显示时有缩放,以及透明度变化
			缩放:0.7 ~ 1.0
			1.0 - scale * 0.3
			透明度 :0.6 ~ 1.0
			0.6 + 0.4 *(1 - scale)

		 *///调用属性动画,设置TransactionX
		float scale = l*1.0f/mMenuWidth;//1 ~ 0


		float rightScale = 0.7f+0.3f*scale;
		float leftScale = 1.0f - scale * 0.3f;
		float leftAlpha = 0.6f + 0.4f * (1 - scale);
		//菜单移动,缩放,透明度设置
		ViewHelper.setTranslationX(mMenu, l);
		ViewHelper.setScaleX(mMenu, leftScale);
		ViewHelper.setScaleY(mMenu, leftScale);
		ViewHelper.setAlpha(mMenu, leftAlpha);

		//内容缩放
		ViewHelper.setPivotX(mContent, 0);//设置mContent缩放的中心点
		ViewHelper.setPivotY(mContent, mContent.getHeight()/2);
		ViewHelper.setScaleX(mContent, rightScale);
		ViewHelper.setScaleY(mContent, rightScale);

	}

我们观察qq5.0会发现,左边菜单显示的时候是,先显示一大部分,还有一小部分隐藏在左边

所以要实现这样的效果:可以一开始把菜单移动改为0.7 ~ 0

ViewHelper.setTranslationX(mMenu, l * 0.7f);

现在以及实现所有效果了

package com.example.slidingmenu.myview;


import com.example.slidingmenu.R;
import com.nineoldandroids.view.ViewHelper;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

public class SlidingMenu extends HorizontalScrollView{

	/**
	 * 未使用自定义属性时使用
	 * @param context
	 * @param attrs
	 * 
	 */
	//水平滚动条
	private LinearLayout mWapper;
	//菜单
	private ViewGroup mMenu;
	//内容区域
	private ViewGroup mContent;
	//屏幕宽度
	private int mScreenWidth;
	private int mMenuWidth;
	//dp
	private int mMenuRightPadding = 50;

	private boolean once;

	//加入boolean类型的变量标识当前的状态(菜单是否打开)
	private boolean isOpen;


	/**
	 * 当使用了自定义的属性时,会调用此构造方法
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */

	public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		// TODO Auto-generated constructor stub
		//获取我们定义的属性
		TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.SlidingMenu, defStyle,0);
		int n = a.getIndexCount();//获得自定义属性的数量
		for (int i = 0; i < n; i++) {
			int attr = a.getIndex(i);//根据下标获得自定义属性
			switch (attr) {
			case R.styleable.SlidingMenu_rightPadding:

				mMenuRightPadding = a.getDimensionPixelSize(attr,
						(int)TypedValue.applyDimension(
								TypedValue.COMPLEX_UNIT_DIP, 50, 
								context.getResources().getDisplayMetrics()));//getDimensionPixelSize()第二个参数是默认值50dp
				break;

			}
		}
		a.recycle();
		//获取屏幕宽度
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(outMetrics);
		mScreenWidth = outMetrics.widthPixels;
		//把dp转换为px
		//		mMenuRightPadding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, 
		//				context.getResources().getDisplayMetrics());
	}
	/*
	 * 什么时候调用一个参数的构造方法:在代码里面new传一个上下文就行了
	 */
	public SlidingMenu(Context context) {
		this(context,null);
		// TODO Auto-generated constructor stub
	}
	public SlidingMenu(Context context, AttributeSet attrs) {

		this(context,attrs,0);
	}
	/**
	 * 设置View的宽和高 设置自己的宽和高
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		/**
		 * 使用once标记使设置宽度的方法只调用一次就行了,没必要多次设置
		 */
		if(!once){
			mWapper = (LinearLayout) getChildAt(0);
			//LinearLayout中的第一个元素
			mMenu = (ViewGroup) mWapper.getChildAt(0);
			//LinearLayout中的第二个元素
			mContent = (ViewGroup) mWapper.getChildAt(1);
			//设置mMenu的宽度
			mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;
			//设置mContent的宽度
			mContent.getLayoutParams().width = mScreenWidth;
			once = true;
		}

		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
	/**
	 * 设置偏移量,将menu隐藏
	 */

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// TODO Auto-generated method stub
		super.onLayout(changed, l, t, r, b);
		//如果发生变化调用,设置偏移量,将menu隐藏
		if(changed){
			//this.scrollTo(x,y)this是滚动条,x为正值时滚动条向左移动,滚动条向右移动内容区域向左移动
			this.scrollTo(mMenuWidth, 0);//y轴不用移动0
		}

	}
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		int action = ev.getAction();
		//因为HorizontalScrollView能自己控制MOVE和Down的事件,即使不做任何处理,它也能把菜单划出来和隐藏,所以这里只需监听一下UP事件就行
		switch (action) {
		case MotionEvent.ACTION_UP:
			int scrollX	= getScrollX();//隐藏左边的宽度,在内容区域左侧多出来的部分(内容部分太大左侧未被屏幕完全显示出来,隐藏在屏幕左边的部分)
			if(scrollX >= mMenuWidth/2){
				this.smoothScrollTo(mMenuWidth, 0);
				//这里使用smoothScrollTo(x,y)方法使有个过渡,因为scrollTo(x,y)是瞬间完成的
				isOpen = false;//将状态设置为关闭状态
			}else {
				//将内容区域完全显示
				this.smoothScrollTo(0, 0);
				isOpen = true;//将状态设置为打开状态
			}	
			return true;
		}
		return super.onTouchEvent(ev);
	}
	/**
	 * 打开菜单
	 */
	public void openMenu(){
		if(isOpen)return;
		this.smoothScrollTo(0, 0);
		isOpen = true;
	}
	public void closeMenu(){
		if(!isOpen)return;
		this.smoothScrollTo(mMenuWidth, 0);
		isOpen = false;
	}
	/**
	 * 切换菜单
	 */
	public void toggle(){
		if(isOpen){
			closeMenu();
		}else{
			openMenu();
		}
	}
	/**
	 * 滚动条变化时的回调方法
	 * 参数1.就是getScrollX
	 * 参数2,3,4是变化的梯度
	 */

	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		// TODO Auto-generated method stub
		super.onScrollChanged(l, t, oldl, oldt);

		/**
		 * 1.内容区域1.0 ~ 0.7缩放效果
			scale :1.0~0.0
			0.7 + 0.3 * scale
			2. 菜单偏移量需要修改

			3.菜单的显示时有缩放,以及透明度变化
			缩放:0.7 ~ 1.0
			1.0 - scale * 0.3
			透明度 :0.6 ~ 1.0
			0.6 + 0.4 *(1 - scale)

		 *///调用属性动画,设置TransactionX
		float scale = l*1.0f/mMenuWidth;//1 ~ 0


		float rightScale = 0.7f+0.3f*scale;
		float leftScale = 1.0f - scale * 0.3f;
		float leftAlpha = 0.6f + 0.4f * (1 - scale);
		//菜单移动,缩放,透明度设置
		ViewHelper.setTranslationX(mMenu, l * 0.5f);//等价于	ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.5f);

		ViewHelper.setScaleX(mMenu, leftScale);
		ViewHelper.setScaleY(mMenu, leftScale);
		ViewHelper.setAlpha(mMenu, leftAlpha);

		//内容缩放
		ViewHelper.setPivotX(mContent, 0);//设置mContent缩放的中心点
		ViewHelper.setPivotY(mContent, mContent.getHeight()/2);
		ViewHelper.setScaleX(mContent, rightScale);
		ViewHelper.setScaleY(mContent, rightScale);

	}
}

总结:

一自定义ViewGroup

1.构造方法的选择,获得一些需要用到的值

2.onMeasure 计算子VIew的宽和高,以及设置自己的宽和高

3.onLayout 决定子View布局的位置

[4.onTouchEvent监听用户的触摸事件]不需要监听用户触摸事件时可以不实现

二构造方法

1.一个参数的context ,自己new 对象的时候使用,传入context上下文对象就行

2.两个参数的,context,attr 布局文件中声明(没有自定义属性的)

3.三个参数,context,attr,defStyle(有自定义的属性)

一般自定义ViewGroup时,三个构造方法都要实现,一个参数的构造方法里调用两个参数的构造方法,两个参数的构造方法调用三个参数的构造方法,

三自定义属性

1.attr.xml

2.布局文件 xmlns = "............../当前应用的包名"

3.在三个参数的构造方法中,获得我们自定义属性的值

4.属性动画




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值