关于SlidingMenu的一些改进写法,仿QQ5.0侧拉缩进

来源:互联网 发布:dkms linux 编辑:程序博客网 时间:2024/06/13 02:07

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);    }

最后运行的结果图片为

这里写图片描述

项目下载地址

0 0
原创粉丝点击