就是这么一个效果!
首先,分析一波:
有两个布局,一个是菜单栏布局,一个是内容布局
看效果,当菜单栏慢慢打开时,内容布局有一个缩放的效果,菜单栏布局也有一个缩放的效果,打开的角度越大,放大的值越大,其次,还有一个透明度的渐变效果,最后就是一个抽屉效果(可以看菜单栏布局的右下角的推出按钮,很明显);
再来看看实现该效果的方式:
下面 直接上代码,按照惯例,会在代码中有大量的注释,如果有问题的,也可以在评论区提出,可以一起交流!毕竟学习使我快乐嘛!哈哈哈哈
1:绘制布局:
<com.justh.dell.kgslidingmenu.SlidingMenu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.justh.dell.kgslidingmenu.MainActivity"
android:background="@drawable/home_menu_bg"
app:menuMarginRight="150dp">
"match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
"@layout/layout_menu"/>
"@layout/layout_content"/>
com.justh.dell.kgslidingmenu.SlidingMenu>
在自定义这个ViewGroup中,有一个自定义属性,app:menuMarginRight,用来代表菜单栏离右边的距离
MenuView(菜单栏)的布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="72dp"
android:orientation="vertical">
<LinearLayout
android:id="@+id/enter_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="23dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/user_head_iv"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/morentouxiang" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="22dp"
android:orientation="vertical">
<TextView
android:id="@+id/user_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="10dp"
android:drawableRight="@drawable/user_write_paint"
android:text="请登录"
android:textColor="#c6b178"
android:textSize="18dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="42dp"
android:orientation="horizontal">
<TextView
android:id="@+id/user_attention_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="10dp"
android:text="关注 0"
android:textColor="#c6b178"
android:textSize="12dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:drawablePadding="10dp"
android:text="粉丝 0"
android:textColor="#c6b178"
android:textSize="12dp" />
LinearLayout>
LinearLayout>
LinearLayout>
<ListView
android:id="@+id/menu_item_lv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@null"
android:dividerHeight="0dp"
android:layout_marginTop="60dp"/>
LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="20dp"
android:text="退出"
android:textColor="#FFFFFF"
android:layout_height="wrap_content" />
RelativeLayout>
内容布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="JUSTH"
android:textSize="30dp"
/>
LinearLayout>
自定义ViewGroup的SlidingMenu类:
public class SlidingMenu extends HorizontalScrollView {
private int mMenuMarginRight = 50;
private int mMenuWidth;
private View mMenuView;
private View mContentView;
//判断当前菜单栏是否打开
private boolean isMenuOpen = false;
//处理手势快速滑动
private GestureDetector mGestureDetector;
//判断当前事件是否被拦截
private boolean isIntercept = false;
public SlidingMenu(Context context) {
this(context,null);
}
public SlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.SlidingMenu);
mMenuMarginRight = (int) array.getDimension(R.styleable.SlidingMenu_menuMarginRight,dp2px(mMenuMarginRight));
mMenuWidth = ScreenUtils.getScreenWidth(context) - mMenuMarginRight;
array.recycle();
mGestureDetector = new GestureDetector(context,new GestureDetectorListener());
}
/**
* 指定menuView和contentView的宽度
*
* 该方法在布局解析完成之后便会调用
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//获取到LinearLayout
ViewGroup container = (ViewGroup) getChildAt(0);
int childCount = container.getChildCount();
//子View只能有两个 一个是菜单view 一个是contentview
if(childCount != 2){
throw new RuntimeException("childCount must have two!");
}
//设置MenuView的宽度
mMenuView = container.getChildAt(0);
ViewGroup.LayoutParams menuParams = mMenuView.getLayoutParams();
menuParams.width = mMenuWidth;
mMenuView.setLayoutParams(menuParams);
//设置ContentView的宽度 这里为全屏显示
mContentView = container.getChildAt(1);
ViewGroup.LayoutParams contentParams = mContentView.getLayoutParams();
contentParams.width = ScreenUtils.getScreenWidth(getContext());
mContentView.setLayoutParams(contentParams);
}
/**
* 随着滑动距离的变化,来缩放以及渐变 平移menuView 和contentView
* 来达到视觉上的效果
* @param l
* @param t
* @param oldl
* @param oldt
*/
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
Log.i("JUSTH",l+"");
//以0.7为基数 缩放contentView
float contentScale = (float) (0.7 + 0.3 * l*1f/mMenuView.getMeasuredWidth());
ViewCompat.setPivotX(mContentView,0);
ViewCompat.setPivotY(mContentView,mContentView.getMeasuredHeight()/2);
ViewCompat.setScaleX(mContentView,contentScale);
ViewCompat.setScaleY(mContentView,contentScale);
//给MenuView设置渐变 基数为0.5
float menuAlpha = (float) (1 - 0.5*l*1f/mMenuView.getMeasuredWidth());
Log.i("JUSTH","ALPHA="+menuAlpha);
ViewCompat.setAlpha(mMenuView,menuAlpha);
//给MenuView设置缩放
float menuScale = (float) (1 - 0.3 * l * 1f/mMenuView.getMeasuredWidth());
ViewCompat.setScaleX(mMenuView,menuScale);
ViewCompat.setScaleY(mMenuView,menuScale);
//设置menuView的抽屉效果
ViewCompat.setTranslationX(mMenuView, 0.25f*l);
}
/**
* 当在滑动的过程中还没关闭的时候抬起手,判断当前应该关闭menuView还是打开menuView
* @param ev
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
//已被事件拦截
if (isIntercept){
return true;
}
//代表当前为手势快速滑动了
if(mGestureDetector.onTouchEvent(ev)){
return true;
}
if(ev.getAction() == MotionEvent.ACTION_UP){
int scrollX = getScrollX();
if(scrollX > mMenuView.getMeasuredWidth()/2){
closeMenu();
}else{
openMenu();
}
//一定要消费事件
return true;
}
return super.onTouchEvent(ev);
}
private void closeMenu(){
smoothScrollTo(mMenuWidth,0);
isMenuOpen = false;
}
private void openMenu(){
smoothScrollTo(0,0);
isMenuOpen = true;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
scrollTo(mMenuWidth,0);
}
private int dp2px(int dp){
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics());
}
//添加手势事件处理
private class GestureDetectorListener extends GestureDetector.SimpleOnGestureListener {
//处理手势快速滑动的方法
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//当手势为左右快速滑动是,则切换状态
if(Math.abs(velocityX) < Math.abs(velocityY)){
//上下滑动的距离大于左右滑动的距离 代表当前为上下滑动
//此时不处理
return super.onFling(e1, e2, velocityX, velocityY);
}
//当velocityX > 0 代表右滑 velocityX < 0 代表左滑
if(isMenuOpen){
//当菜单栏打开的时候,快速左滑,关闭菜单栏
if(velocityX < 0){
closeMenu();
return true;
}
}else {
if(velocityX > 0){
openMenu();
return true;
}
}
return super.onFling(e1, e2, velocityX, velocityY);
}
}
//处理时间拦截 当菜单栏打开的时候,点击右侧内容页面 关闭菜单栏 且拦截内容页面的所有事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
isIntercept = false;
if(isMenuOpen){
int x = (int) ev.getX();
if(x > mMenuView.getMeasuredWidth()){
closeMenu();
isIntercept = true;
return true;
}
}
return super.onInterceptTouchEvent(ev);
}
}