仿QQ侧滑菜单
前言
- Google官方已推出DrawerLayout和NavigationView作为MD设计的侧边栏,效果简洁大方,但是国内的app标准参差不齐,众口难调才不管你什么官方的呢,我开心就好,但基本也是遵循这大企业的路子走的,所以今天就写一个仿照QQ侧滑的练练手吧,因为不想引入其他太多的MD内容,所以还是用的基本的方法去写,这样更纯粹一点。
效果分析
- 侧滑是一个水平横向的手势操作,操作的对象是两个相对独立的界面,而且每个界面有可能有自己的手势操作,怎样能够方便的避免彼此的手势冲突,而且动态的达到自己的目的呢,最简单的方式是采用当前可以水平滑动的控件:HorizantalScrollView.
- 既然外围框架决定了是HorizantalScrollView,那么手势部分是一定要改写,同时避免与自布局的收拾冲突,所以在必要的手势中需要获取手势操作所有权,但是HorizantalScrollView的自布局摆放方式是从第一个开始水品展开的,这与我们主界面默认遮挡住菜单的样子不同哦,所以除了改写收拾方法还需要改写它的位置拜访效果,综上所述我们需要改写的主要方法是:OnTouchEvent(或者其他收拾监听)、OnMeasure()\OnLayout,同时为了方便我们细化手势处理的效果,我们可以在细致的重写OnScrollChange()方法,将滑动的效果做到极致。
项目实战
-自定义View Java实现
package com.jx.org.ctmtestdemo;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
/**
* Created by J_X on 2016/10/19.
* 仿qq侧滑
*/
public class MySlidingMenu extends HorizontalScrollView {
/**
* 左边侧边栏
*/
private ViewGroup leftView;
/**
* 右边主界面内容
*/
private ViewGroup rightView;
/**
* 屏幕宽度
*/
private int mScreenWidth;
/**
* 子控件是第一次测量确认尺寸么
*/
private boolean isFirstMeasure = true;
/**
* 左边侧边计算后的最终宽度
*/
private int leftWidth;
/**
* 手指按下相对于屏幕左上角的高度
*/
private float touchDownX;
/**
* 左边侧边占据屏幕宽度的比例
*/
private final float SLIDE_MENU_BY_WINDOW_SCALE = 0.75f;
public MySlidingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
setScrollbarFadingEnabled(true);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
touchDownX = ev.getX();
break;
case MotionEvent.ACTION_UP:
float disX = ev.getX() - touchDownX;
//leftWidth/4是屏幕的3/16的大小,侧滑效果比较友好
if (disX > leftWidth / 4) {
//向右滑动是正数, 左边滑动侧边栏的左侧位置(整个HorizantalScrollView的最左边缘),这样就打开的侧边栏
this.smoothScrollTo(0, 0);
} else {
//向左滑动是负数, 左边滑动侧边栏的右侧位置,这样就关闭的侧边栏
this.smoothScrollTo(mScreenWidth, 0);
}
//消费掉该事件避免子控件冲突
return true;
}
return super.onTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (isFirstMeasure) {
//在这里面做特效处理
//1.平移效果(兼容2.x,nineOldeAndroid.jar)
//滑动的速度应该比主界面慢一点
//2.缩放效果
// float leftScale = 1-0.4f*factor;
// ViewHelper.setScaleX(mMenu, leftScale);
// ViewHelper.setScaleY(mMenu, leftScale);
//
// float rightScale = 0.8f+0.2f*factor;
// ViewHelper.setScaleX(mMain, rightScale);
// ViewHelper.setScaleY(mMain, rightScale);
// //3.透明度效果
// ViewHelper.setAlpha(mMenu, 1-factor);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isFirstMeasure) {
LinearLayout wrapper = (LinearLayout) getChildAt(0);
leftView = (ViewGroup) wrapper.getChildAt(0);
rightView = (ViewGroup) wrapper.getChildAt(1);
leftWidth = (int) (mScreenWidth * SLIDE_MENU_BY_WINDOW_SCALE);
leftView.getLayoutParams().width = leftWidth;
rightView.getLayoutParams().width = mScreenWidth;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//默认情况下,将左侧侧边栏隐藏,只显示主界面
this.scrollTo(leftWidth, 0);
isFirstMeasure = false;
super.onLayout(changed, l, t, r, b);
}
}
-自定义View xml使用部分:但是有限制哦,因为没有对自布局进行判断处理呢
<?xml version="1.0" encoding="utf-8"?>
<com.jx.org.ctmtestdemo.MySlidingMenu xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<include layout="@layout/main_menu" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
</LinearLayout>
</com.jx.org.ctmtestdemo.MySlidingMenu>
总结
-主要可能出错的问题就是需要计算自布局的宽度
-需要注意的地方就布局的默认摆放位置,因为默认SlidingMenu是默认显示的
-注意MotionEvent.getX()和View.getX()意义的区别哦,不然手势处理计算就会凌乱