SlidingMenu的使用教程很多,如果只需要简单的侧拉,使用如下的办法简单加载
点击SlidingMenu下载
首先下载完毕导入项目中,导入方式如图
这时还没有玩,slidingMenu在文件夹下另一个包中,包名为library如图(点击确定)
完成后开始记得看下app > build.gradle 是不是有这个项目的引用,么有就自己写,有就当这句话不存在。
之后开始配置menu的初始信息
private void loadMenu() {
//获取屏幕的宽度
int with = ScreenUtils.getScreenWidth(this);
//初始化侧边栏
menu = new SlidingMenu(this);
menu.setMode(SlidingMenu.LEFT);
// 设置触摸屏幕的模式
menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
//设置SlidingMenu菜单的宽度
menu.setBehindWidth(with / 2);
// menu.setShadowDrawable(R.drawable.shadow);//设置阴影图片
// menu.setShadowWidthRes(R.dimen.shadow_width);//设置阴影图片的宽度
menu.setBackgroundColor(Color.BLACK);
// 设置渐入渐出效果的值
menu.setFadeDegree(0.35f);
menu.attachToActivity(MainActivity.this, SlidingMenu.SLIDING_CONTENT);
//为侧滑菜单设置布局
menu.setMenu(R.layout.slidingmenuleft);
}
ScreenUtils 是我自己的工具类,代码如下,主要是设置menu拉出来的宽度的
/**
* @product: QCY_Sport
* @Description: 屏幕相关辅助类 (用一句话描述该文件做什么)
* @author: 朱亮(171422696@qq.com)
* Date: 2016-11-22
* Time: 15:58
* @company:蓝米科技 version V1.0
*/
public class ScreenUtils {
/**
* 获得屏幕相关的辅助类
*/
private ScreenUtils()
{
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* 获得屏幕高度
*
* @param context
* @return
*/
public static int getScreenWidth(Context context)
{
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
/**
* 获得屏幕宽度
*
* @param context
* @return
*/
public static int getScreenHeight(Context context)
{
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
/**
* 获得状态栏的高度
*
* @param context
* @return
*/
public static int getStatusHeight(Context context)
{
int statusHeight = -1;
try
{
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e)
{
e.printStackTrace();
}
return statusHeight;
}
/**
* 获取当前屏幕截图,包含状态栏
*
* @param activity
* @return
*/
public static Bitmap snapShotWithStatusBar(Activity activity)
{
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
view.destroyDrawingCache();
return bp;
}
/**
* 获取当前屏幕截图,不包含状态栏
*
* @param activity
* @return
*/
public static Bitmap snapShotWithoutStatusBar(Activity activity)
{
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
- statusBarHeight);
view.destroyDrawingCache();
return bp;
}
}
slidingmenuleft.xml布局是自己定义的一个圆形头像CircleImageView还有自己的一些颜色配置colors, 这些都是需要你自己根据个人情况来设置的,里面有个自定义view的头像,这里改成自己的。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.org.zl.slidingmenudemo.myView.CircleImageView
android:id="@+id/circleImageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/headportrait"
android:layout_gravity="center"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="二狗子"
android:textSize="20dp"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:textColor="@color/colorWhite"
android:id="@+id/textView"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_margin="10dp"
android:background="@color/colorAccent"
/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/setSound"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="音效设置"
android:drawableLeft="@drawable/back"
android:drawablePadding="20dp"
android:layout_marginLeft="10dp"
android:layout_marginBottom="25dp"
android:textColor="@color/colorWhite"
/>
<TextView
android:id="@+id/skinCenter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="皮肤中心"
android:drawableLeft="@drawable/back"
android:drawablePadding="20dp"
android:layout_marginLeft="10dp"
android:layout_marginBottom="25dp"
android:textColor="@color/colorWhite"
/>
<TextView
android:id="@+id/mySongList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我的歌单"
android:drawableLeft="@drawable/back"
android:drawablePadding="20dp"
android:layout_marginLeft="10dp"
android:layout_marginBottom="25dp"
android:textColor="@color/colorWhite"
/>
<TextView
android:id="@+id/feedBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="意见反馈"
android:drawableLeft="@drawable/back"
android:drawablePadding="20dp"
android:layout_marginLeft="10dp"
android:layout_marginBottom="25dp"
android:textColor="@color/colorWhite"
/>
<TextView
android:id="@+id/about"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关于"
android:drawableLeft="@drawable/back"
android:drawablePadding="20dp"
android:layout_marginLeft="10dp"
android:layout_marginBottom="25dp"
android:textColor="@color/colorWhite"
/>
<TextView
android:id="@+id/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="搜索"
android:drawableLeft="@drawable/back"
android:drawablePadding="20dp"
android:layout_marginLeft="10dp"
android:layout_marginBottom="25dp"
android:textColor="@color/colorWhite"
/>
</LinearLayout>
</LinearLayout>
最后别忘记,在onDestroy()中加上一句代码
@Override
protected void onDestroy() {
if(menu.isSlidingEnabled()){
menu.showContent();
}
super.onDestroy();
}
任务完成,运行图片为
这是SlidingMenu的最简单的加载,现在需求变了需要变成侧拉缩进如下图
查看代码可以知道menu中有个方法setBehindCanvasTransformer()
这个方法是用在menu拉出来和缩回去的效果配置的,我们根据这个方法来达到自己的需求
menu.setBehindCanvasTransformer(
new SlidingMenu.CanvasTransformer() {
@Override
public void transformCanvas(Canvas canvas, float percentOpen) {
//percentOpen的值(0~1)之间
float scale = 0.75f + 0.25f * percentOpen;
canvas.scale(scale, scale, -canvas.getWidth() / 2, canvas.getHeight() / 2);
}
});
这时,percentOpen 会在menu拉到最大的时候达到1,侧拉框完全显现,如果设置 float scale = 0.75f ;固定值时,效果如下
可以查看源码 SlidingMenu下
public void setBehindCanvasTransformer(CanvasTransformer t) {
mViewBehind.setCanvasTransformer(t);
}
这里面传入了一个CanvasTransformer 观察者,这个观察者在什么时候被调用呢,继续点进mViewBehind.setCanvasTransformer(t);中发现观察者被传入了setCanvasTransformer方法中,查找引用最终在
dispatchDraw找到,这是ViewGroup的绘制方法,有背景就调用onDraw方法,同时里面包含dispatchDraw方法,无背景时,直截调用dispatchDraw方法,所以….
@Override
protected void dispatchDraw(Canvas canvas) {
if (mTransformer != null) {
canvas.save();
//绘制的过程中回调观察者
mTransformer.transformCanvas(canvas, mViewAbove.getPercentOpen());
super.dispatchDraw(canvas);
canvas.restore();
} else
super.dispatchDraw(canvas);
}
但是在这里没有找到invalidate()啊,于是继续找,在本类中找到
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
if (mTransformer != null)
invalidate();
}
scrollTo又被scrollBehindTo调用,scrollBehindTo又被CustomViewAbove的scrollTo调用
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
mScrollX = x;
mViewBehind.scrollBehindTo(mContent, x, y);
((SlidingMenu)getParent()).manageLayers(getPercentOpen());
}
CustomViewAbove的scrollTo又被本类的onSizeChanged调用,
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Make sure scroll position is set correctly.
if (w != oldw) {
// [ChrisJ] - This fixes the onConfiguration change for orientation issue..
// maybe worth having a look why the recomputeScroll pos is screwing
// up?
completeScroll();
scrollTo(getDestScrollX(mCurItem), getScrollY());
}
}
最终CustomViewAbove被SlidingMenu初始化进addView中,明白了左边的拉框的原理,相同的道理,改变右边推框的也应该没问题
SlidingMenu加载了两个ViewGroup 一个是 CustomViewBehind,一个是CustomViewAbove,侧拉框在CustomViewBehind被处理,我们只需要改变CustomViewAbove的代码即可,代码和CustomViewBehind相同,逆推回去,添加相同的观察者即可,在SlidingMenu中添加一句代码
public void setAboveCanvasTransformer(CanvasTransformer t) {
mViewAbove.setCanvasTransformer(t);
}
这时必然会报错,因为CustomViewAbove没有setCanvasTransformer方法,需要自己添加进入一个观察者
public void setCanvasTransformer(SlidingMenu.CanvasTransformer t) {
mTransformer = t;
}
同时类上要声明观察者
private SlidingMenu.CanvasTransformer mTransformer;
观察者传入之后,需要确定在什么地方观察,这里可以参考CustomViewBehind里的观察者代码,发现有几个地方需要观察的
第一个是scrollTo 方法
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
mScrollX = x;
mViewBehind.scrollBehindTo(mContent, x, y);
((SlidingMenu)getParent()).manageLayers(getPercentOpen());
if (mTransformer != null)
invalidate();
}
第二个是dispatchDraw方法
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
// Draw the margin drawable if needed.
mViewBehind.drawShadow(mContent, canvas);
mViewBehind.drawFade(mContent, canvas, getPercentOpen());
mViewBehind.drawSelector(mContent, canvas, getPercentOpen());
if (mTransformer != null) {
canvas.save();
mTransformer.transformCanvas(canvas, getPercentOpen());
super.dispatchDraw(canvas);
canvas.restore();
} else
super.dispatchDraw(canvas);
}
还有一点,尽量将CustomViewAbove类中的FloatMath 改成 Math
float distanceInfluenceForSnapDuration(float f) {
f -= 0.5f; // center the values about 0.
f *= 0.3f * Math.PI / 2.0f;
//这里改成Math.
return (float) Math.sin(f);
}
观察者写完了,进行最后一步,实现它
//设置activity层内容UI移动效果
//此方法为slidingmenu中自己增加的方法
menu.setAboveCanvasTransformer(new SlidingMenu.CanvasTransformer() {
@Override
public void transformCanvas(Canvas canvas, float percentOpen) {
float scale = 1f - 0.25f * percentOpen;
canvas.scale(scale, scale, 0, canvas.getHeight() / 2);
}
});
设置完毕准备运行,最后运行发现activity重叠,如图
这里真的发了很长时间找问题,各种比较,最后找到这里
CustomViewAbove下的dispatchDraw()除了问题,因为我们改过里面的代码,而CustomViewBehind里的super.dispatchDraw(canvas);是经过逻辑的,而CustomViewAbove是直接返回的,所以,注释掉就好
复制下面代码黏贴:
@Override
protected void dispatchDraw(Canvas canvas) {
// super.dispatchDraw(canvas);
// Draw the margin drawable if needed.
mViewBehind.drawShadow(mContent, canvas);
mViewBehind.drawFade(mContent, canvas, getPercentOpen());
mViewBehind.drawSelector(mContent, canvas, getPercentOpen());
if (mTransformer != null) {
canvas.save();
mTransformer.transformCanvas(canvas, getPercentOpen());
super.dispatchDraw(canvas);
canvas.restore();
} else
super.dispatchDraw(canvas);
}
最后运行的结果图片为