关于SlidingMenu的一些改进写法,仿QQ5.0侧拉缩进_android slidemenu setbehindwidthres设置左右平分-程序员宅基地

技术标签: app  qq  library  android  menu  

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: 朱亮([email protected])
 * 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);
    }

最后运行的结果图片为

这里写图片描述

项目下载地址

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/z171422696/article/details/54575011

智能推荐

使用nginx解决浏览器跨域问题_nginx不停的xhr-程序员宅基地

文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr

在 Oracle 中配置 extproc 以访问 ST_Geometry-程序员宅基地

文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc

Linux C++ gbk转为utf-8_linux c++ gbk->utf8-程序员宅基地

文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8

IMP-00009: 导出文件异常结束-程序员宅基地

文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束

python程序员需要深入掌握的技能_Python用数据说明程序员需要掌握的技能-程序员宅基地

文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求

Spring @Service生成bean名称的规则(当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致)_@service beanname-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname

随便推点

二叉树的各种创建方法_二叉树的建立-程序员宅基地

文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include&lt;stdio.h&gt;#include&lt;string.h&gt;#include&lt;stdlib.h&gt;#include&lt;malloc.h&gt;#include&lt;iostream&gt;#include&lt;stack&gt;#include&lt;queue&gt;using namespace std;typed_二叉树的建立

解决asp.net导出excel时中文文件名乱码_asp.net utf8 导出中文字符乱码-程序员宅基地

文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码

笔记-编译原理-实验一-词法分析器设计_对pl/0作以下修改扩充。增加单词-程序员宅基地

文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词

android adb shell 权限,android adb shell权限被拒绝-程序员宅基地

文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限

投影仪-相机标定_相机-投影仪标定-程序员宅基地

文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定

Wayland架构、渲染、硬件支持-程序员宅基地

文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland

推荐文章

热门文章

相关标签