HorizontalScrollView实现侧滑菜单

1. 一般侧滑的实现
ViewGroup Menu + Content
onTouchEvent
MOVE: ViewGroup的leftMargin
UP:根据现实菜单的宽度,决定将其隐藏或者显示

自定义ViewGroup
onMesure  决定内部View(子View)的宽和高,决定自己的宽和高
onLayout    决定子View 放置的位置
onTouchEvent 判断状态来移动效果  

抽屉式侧滑
区别:菜单仿佛在内容区域底下
mMenuWidth
100dp mMenuWidth - 100
200dp mMenuWidth - 200
属性动画(Android 3.0) :TranslationX
getScroll:mMenuWidth ~ 0 //显示过程
调用动画时机:ACTION_MOVE

区别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

动画:点击下载jar包


package com.zzc.view;

import com.example.message.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.MonthDisplayHelper;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.TranslateAnimation;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
public class SlidingMenu extends HorizontalScrollView {

	private LinearLayout mWapper;// HorizontalScrollView下唯
	private ViewGroup mMenu;// 菜单
	private ViewGroup mContent;// 内容
	private int mScreenWidth;// 屏幕宽度
	private int mMenuRightPadding = 50;
	private int mMenuWdith;// 菜单宽度
	private boolean isOpen;// 是否已经打开
	private boolean once;// 用来保证单次执行onMeasure方法

	public SlidingMenu(Context context) {
		this(context, null);
	}

	/**
	 * 未使用自定义属性时调用
	 * 
	 * @param context
	 * @param attrs
	 */
	public SlidingMenu(Context context, AttributeSet attrs) {
		this(context, attrs, 0);

	}

	/**
	 * 使用自定义属性时调用此构造方法
	 * 
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
				R.styleable.SlidingMenu, defStyle, 0);
		init(context, a);
	}

	/**
	 * 初始化菜单离
	 * @param context
	 * @param a
	 */
	private void init(Context context, TypedArray a) {
		// 获取数量用来遍历
		int n = a.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = a.getIndex(i);
			switch (attr) {
			case R.styleable.SlidingMenu_rightPadding:
				//用来获取设置的值 默认值为50dp
				mMenuRightPadding = a.getDimensionPixelSize(attr,
						(int) TypedValue.applyDimension(
								TypedValue.COMPLEX_UNIT_DIP, 50, context
										.getResources().getDisplayMetrics()));
				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());
	}

	/**
	 * 设置子View的宽和高 ,自己的宽和高
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		if (!once) {
			mWapper = (LinearLayout) getChildAt(0);
			mMenu = (ViewGroup) mWapper.getChildAt(0);
			mContent = (ViewGroup) mWapper.getChildAt(1);
			// 菜单的宽度
			mMenuWdith = mMenu.getLayoutParams().width = mScreenWidth
					- mMenuRightPadding;
			// 内容的宽度
			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) {
		super.onLayout(changed, l, t, r, b);
		if (changed) {
			// 默认隐藏menu
			this.scrollTo(mMenuWdith, 0);
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		//如果显示区域大于菜单宽度一半则完全显示,否则隐藏  
		case MotionEvent.ACTION_UP:
			// 内容的0起点 到menu右边缘的x值 用来判断抬起时menu是否隐藏
			int scrllX = getScrollX();
			if (scrllX >= mMenuWdith / 2) {
				//scrollTo是瞬间完成 smoothScrollTo内部有动画效果
				this.smoothScrollTo(mMenuWdith, 0);
				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(mMenuWdith, 0);
		isOpen = false;
	}
	
	/**
	 * 切换菜单
	 */
	public void toggle(){
		if(isOpen){
			closeMenu();
		}else{
			openMenu();
		}
	}
	
	/**
	 * 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) {
		super.onScrollChanged(l, t, oldl, oldt);
		float scale = l * 1.0f/mMenuWdith;//1 ~ 0
		float rightScale = 0.7f + 0.3f * scale;
		float leftScale = 1.0f - scale * 0.3f;
		float leftAlpha = 0.6f + 0.4f * (1 - scale);
		//调用属性动画,设置TranslationX  用的nineoldandroids为了保持向下的兼容
		ViewHelper.setTranslationX(mMenu, mMenuWdith * scale * 0.8f);
		//设置menu缩放
		ViewHelper.setScaleX(mMenu, leftScale);
		ViewHelper.setScaleY(mMenu, leftScale);
		//设置menu透明度变化
		ViewHelper.setAlpha(mMenu, leftAlpha);
		//设置mContent缩放的中心点
		ViewHelper.setPivotX(mContent, 0);
		ViewHelper.setPivotY(mContent,mContent.getHeight()/2);
		//设置mContent缩放
		ViewHelper.setScaleX(mContent, rightScale);
		ViewHelper.setScaleY(mContent, rightScale);
	}
}

2.menu.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical" >

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

            <ImageView
                android:id="@+id/id_img1"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/ic_launcher" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_toRightOf="@id/id_img1"
                android:text="第一个item"
                android:textSize="20sp" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

            <ImageView
                android:id="@+id/id_img2"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/ic_launcher" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_toRightOf="@id/id_img2"
                android:text="第二个item"
                android:textSize="20sp" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

            <ImageView
                android:id="@+id/id_img3"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/ic_launcher" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_toRightOf="@id/id_img3"
                android:text="第三个item"
                android:textSize="20sp" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

            <ImageView
                android:id="@+id/id_img4"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/ic_launcher" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_toRightOf="@id/id_img4"
                android:text="第四个item"
                android:textSize="20sp" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

            <ImageView
                android:id="@+id/id_img5"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/ic_launcher" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_toRightOf="@id/id_img5"
                android:text="第五个item"
                android:textSize="20sp" />
        </RelativeLayout>
    </LinearLayout>

</RelativeLayout>

3.加载SlidingMenu
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:menu="http://schemas.android.com/apk/res/com.example.message"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.zzc.view.SlidingMenu
        android:id="@+id/sliding_menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        menu:rightPadding="60dp" >

        <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/bb" >
                <Button 
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="切换"
                    android:onClick="toogle"/>
            </LinearLayout>
        </LinearLayout>
    </com.zzc.view.SlidingMenu>

</RelativeLayout>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值