改进Android SlidingMenu实现QQ样式边侧滑抽屉技术

简介: 改进Android SlidingMenu实现QQ样式边侧滑抽屉技术我在之前写的附录文章1中介绍了Android SlidingMenu的使用,Android SlidingMenu作为第三方的边侧滑技术(也被称之为‘抽屉’),在过去的四五年中被广泛使用,但随着后来谷歌官方在Android中以官方支持的形式相继推出了DrawerLayout(附录文章2)和NavigationView(附录文章3)作为抽屉技术的标准实现后,SlidingMenu逐渐在边缘化。

改进Android SlidingMenu实现QQ样式边侧滑抽屉技术

我在之前写的附录文章1中介绍了Android SlidingMenu的使用,Android SlidingMenu作为第三方的边侧滑技术(也被称之为‘抽屉’),在过去的四五年中被广泛使用,但随着后来谷歌官方在Android中以官方支持的形式相继推出了DrawerLayout(附录文章2)和NavigationView(附录文章3)作为抽屉技术的标准实现后,SlidingMenu逐渐在边缘化。在以后的开发中,如果要实现抽屉的边侧滑效果,DrawerLayout和NavigationView是首选。
但是,SlidingMenu在过去毕竟盛行过,一些老旧的APP中作为继承和惯性,还在使用SlidingMenu。如果瞬间说抛弃SlidingMenu,代码切换的时间和工作量有些多。
这篇文章要写的是,如何在不改变SlidingMenu的主题结构情况下,对SlidingMenu进行代码改造和增强,实现类似QQ的边侧滑抽屉效果。
在一段时间,QQ手机客户端的边侧滑(抽屉),和SlidingMenu一样,左滑右滑切换出隐藏的菜单和功能界面,但是需要特别注意的是:QQ的边侧滑与普通的SlidingMenu边侧滑效果不同,QQ的边侧滑、当抽屉打开时候,是一种逐渐缩进缩出的放大/缩小进出效果,同时还带有一定的电影中屏幕逐渐亮/暗效果。本文将在SlidingMenu的基础上改进SlidingMenu代码,作为兼容和增强,实现QQ样式的边侧滑抽屉效果。
写一个布局文件,主布局,通常在实际的开发中,这就是要盛放主体内容的界面activity_main.xml,我简单写一个布局,主要用于测试:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"
    android:background="#FF6F00" >  
      
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerInParent="true" 
        android:textColor="@android:color/white" 
        android:textSize="80sp"
        android:gravity="center"
        android:text="Zhang Phil" />  
  
</RelativeLayout>


MainActivity.java:

package zhangphil.slidingmenu;

import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu.CanvasTransformer;
import com.nineoldandroids.view.ViewHelper;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class MainActivity extends FragmentActivity {

	private SlidingMenu mSlidingMenu;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);

		mSlidingMenu = new SlidingMenu(this);

		mSlidingMenu.setMode(SlidingMenu.LEFT);
		mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);
		mSlidingMenu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);

		// 左边
		mSlidingMenu.setMenu(R.layout.left_menu);

		Fragment leftFragment = TestFragment.newInstance();
		FragmentManager fm = getSupportFragmentManager();
		FragmentTransaction ft = fm.beginTransaction();
		ft.replace(R.id.left, leftFragment);
		ft.commit();

		// 核心关键处,这就是对SlideMenu的增强和改进。
		addQQSlideStyleSlide();
	}

	// 为SlideMenu添加QQ样式的边侧滑
	private void addQQSlideStyleSlide() {

		CanvasTransformer mTransformer = new CanvasTransformer() {

			@Override
			public void transformCanvas(Canvas canvas, float percentOpen) {

				View mainContent = mSlidingMenu.getContent();
				View leftContent = mSlidingMenu.getMenu();

				animateView(mainContent, leftContent, percentOpen);
			}
		};

		// 设置滑动菜单视图的宽度
		mSlidingMenu.setBehindOffsetRes(R.dimen.slidingmenu_offset);

		mSlidingMenu.setFadeEnabled(false);

		mSlidingMenu.setBehindCanvasTransformer(mTransformer);
	}

	private void animateView(View main, View left, float percent) {
		float f1 = 1 - percent * 0.3f;
		ViewHelper.setScaleX(main, f1);
		ViewHelper.setScaleY(main, f1);
		ViewHelper.setTranslationX(left, -left.getWidth() / 2.3f + left.getWidth() / 2.3f * percent);
		ViewHelper.setScaleX(left, 0.5f + 0.5f * percent);
		ViewHelper.setScaleY(left, 0.5f + 0.5f * percent);
		ViewHelper.setAlpha(left, percent);

		getWindow().getDecorView().getBackground().setColorFilter(evaluate(percent, Color.BLACK, Color.TRANSPARENT),
				Mode.SRC_OVER);
	}

	private Integer evaluate(float fraction, Object startValue, Integer endValue) {
		int startInt = (Integer) startValue;
		int startA = (startInt >> 24) & 0xff;
		int startR = (startInt >> 16) & 0xff;
		int startG = (startInt >> 8) & 0xff;
		int startB = startInt & 0xff;
		int endInt = (Integer) endValue;
		int endA = (endInt >> 24) & 0xff;
		int endR = (endInt >> 16) & 0xff;
		int endG = (endInt >> 8) & 0xff;
		int endB = endInt & 0xff;
		return (int) ((startA + (int) (fraction * (endA - startA))) << 24)
				| (int) ((startR + (int) (fraction * (endR - startR))) << 16)
				| (int) ((startG + (int) (fraction * (endG - startG))) << 8)
				| (int) ((startB + (int) (fraction * (endB - startB))));
	}

	//
	// 仅仅用于生成测试的Fragment。
	// 左边侧边滑打开的抽屉
	//
	public static class TestFragment extends Fragment {

		public static Fragment newInstance() {
			Fragment fragment = new TestFragment();
			return fragment;
		}

		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

			// 仅仅显示一个TextView。
			TextView tv = new TextView(getActivity());
			tv.setTextColor(Color.WHITE);
			tv.setText("左边");
			tv.setTextSize(60.0f);
			tv.setGravity(Gravity.CENTER);

			return tv;
		}
	}
}


在自己的代码中如何使用SlideMenu本文不再详细介绍,我写的附录文章1有介绍。
如何对SlidingMenu进行改造以实现QQ样式的边侧滑抽屉技术,核心关键处就是我写在MainActivity.java里面的这部分连锁代码:

// 为SlideMenu添加QQ样式的边侧滑
	private void addQQSlideStyleSlide() {

		CanvasTransformer mTransformer = new CanvasTransformer() {

			@Override
			public void transformCanvas(Canvas canvas, float percentOpen) {

				View mainContent = mSlidingMenu.getContent();
				View leftContent = mSlidingMenu.getMenu();

				animateView(mainContent, leftContent, percentOpen);
			}
		};

		// 设置滑动菜单视图的宽度
		mSlidingMenu.setBehindOffsetRes(R.dimen.slidingmenu_offset);

		mSlidingMenu.setFadeEnabled(false);

		mSlidingMenu.setBehindCanvasTransformer(mTransformer);
	}

	private void animateView(View main, View left, float percent) {
		float f1 = 1 - percent * 0.3f;
		ViewHelper.setScaleX(main, f1);
		ViewHelper.setScaleY(main, f1);
		ViewHelper.setTranslationX(left, -left.getWidth() / 2.3f + left.getWidth() / 2.3f * percent);
		ViewHelper.setScaleX(left, 0.5f + 0.5f * percent);
		ViewHelper.setScaleY(left, 0.5f + 0.5f * percent);
		ViewHelper.setAlpha(left, percent);

		getWindow().getDecorView().getBackground().setColorFilter(evaluate(percent, Color.BLACK, Color.TRANSPARENT),
				Mode.SRC_OVER);
	}

	private Integer evaluate(float fraction, Object startValue, Integer endValue) {
		int startInt = (Integer) startValue;
		int startA = (startInt >> 24) & 0xff;
		int startR = (startInt >> 16) & 0xff;
		int startG = (startInt >> 8) & 0xff;
		int startB = startInt & 0xff;
		int endInt = (Integer) endValue;
		int endA = (endInt >> 24) & 0xff;
		int endR = (endInt >> 16) & 0xff;
		int endG = (endInt >> 8) & 0xff;
		int endB = endInt & 0xff;
		return (int) ((startA + (int) (fraction * (endA - startA))) << 24)
				| (int) ((startR + (int) (fraction * (endR - startR))) << 16)
				| (int) ((startG + (int) (fraction * (endG - startG))) << 8)
				| (int) ((startB + (int) (fraction * (endB - startB))));
	}



以下这部分代码,主要是为了实现背景逐渐点亮/逐渐暗淡的效果。

getWindow().getDecorView().getBackground().setColorFilter(evaluate(percent, Color.BLACK, Color.TRANSPARENT),
				Mode.SRC_OVER);


需要设置SlideMenu侧滑打开抽屉后的偏移距离,否则左边打开的窗口Menu将和普通的SlideMenu一样将完全展开铺满整个窗口,达不到QQ的那种各个窗口占据一般的效果。

Values/dimens.xml:

<dimen name="slidingmenu_offset">150dp</dimen>


测试的左边侧边滑打开的抽屉后,加载的Fragment使用的布局left.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#4FC3F7"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/left"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#F44336" >
    </FrameLayout>

</LinearLayout>


代码写到这里,像QQ样式的边侧滑打开抽屉技术已经实现,但仍有一个细节未实现。QQ边侧滑打开抽屉时候,注意整个屏幕窗口内的背景图,好像是一个星空,要在自己的代码中也有这个背景,那么需要需要对我们自己的Activity略做修改,修改values目录下styles.xml文件主题,把要实现QQ边侧滑抽屉效果的Activity的Theme背景添加一张图片,图片需要事先放到drawable目录,我的这个例子,事先在drawable目录下放一张zhangphil_background.jpg图片:

<resources>

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="android:Theme.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    
    	<!-- zhang phil增加的背景,作为QQ样式边侧滑打开抽屉时候整个窗体背景图-->
    	<item name="android:windowBackground">@drawable/zhangphil_background</item>
    </style>

</resources>



代码运行结果(初始状态 –> 然后,从左往右的边侧滑,抽屉逐渐打开):



附录文章:
1,《集成Android SlidingMenu(SlideMenu)》链接地址:http://blog.csdn.net/zhangphil/article/details/44078805
2,《基于Android官方DrawerLayout实现抽屉导航菜单》链接地址:http://blog.csdn.net/zhangphil/article/details/48710453
3,《Android Material Design: NavigationView抽屉导航菜单》链接地址:http://blog.csdn.net/zhangphil/article/details/48931221

相关文章
|
3月前
|
存储 Java 开发工具
Android开发的技术与开发流程
Android开发的技术与开发流程
142 1
|
7月前
|
开发工具 Android开发
Android平台GB28181设备接入端语音广播技术探究和填坑指南
GB/T28181-2016官方规范和交互流程,我们不再赘述。
|
7月前
|
编解码 Android开发 数据安全/隐私保护
Android平台外部编码数据(H264/H265/AAC/PCMA/PCMU)实时预览播放技术实现
好多开发者可能疑惑,外部数据实时预览播放,到底有什么用? 是的,一般场景是用不到的,我们在开发这块前几年已经开发了非常稳定的RTMP、RTSP直播播放模块,不过也遇到这样的场景,部分设备输出编码后(视频:H.264/H.265,音频:AAC/PCMA/PCMU)的数据,比如无人机或部分智能硬件设备,回调出来的H.264/H.265数据,除了想转推到RTMP、轻量级RTSP服务或GB28181外,还需要本地预览甚至对数据做二次处理(视频分析、实时水印字符叠加等,然后二次编码),基于这样的场景诉求,我们开发了Android平台外部编码数据实时预览播放模块。
|
6月前
|
存储 传感器 定位技术
《移动互联网技术》 第四章 移动应用开发: Android Studio开发环境的使用方法:建立工程,编写源程序,编译链接,安装模拟器,通过模拟器运行和调试程序
《移动互联网技术》 第四章 移动应用开发: Android Studio开发环境的使用方法:建立工程,编写源程序,编译链接,安装模拟器,通过模拟器运行和调试程序
64 0
|
20天前
|
Android开发
Android自带的DrawerLayout和ActionBarDrawerToggle实现侧滑效果
Android自带的DrawerLayout和ActionBarDrawerToggle实现侧滑效果
10 0
|
2月前
|
人工智能 vr&ar Android开发
探索安卓与iOS系统的技术进展
【2月更文挑战第4天】本文将探讨安卓与iOS两大操作系统在最新技术进展方面的差异与相似之处。我们将分析它们在人工智能、增强现实、隐私保护等方面的创新和发展,并展望未来可能出现的趋势。通过对比这两个操作系统的技术特点,读者将能够更好地了解并选择适合自己需求的智能设备。
|
7月前
|
开发工具 Android开发
Android平台GB28181设备接入端预置位查询(PresetQuery)探讨和技术实现
之前blog介绍了GB28181云台控制(PTZCmd)相关,本文主要是介绍下GB28181预置位查询。
|
3月前
|
安全 算法 JavaScript
安卓逆向 -- 关键代码定位与分析技术
安卓逆向 -- 关键代码定位与分析技术
39 0
|
3月前
|
SQL API Android开发
展望2022:Android 开发最新技术动向
展望2022:Android 开发最新技术动向
107 0
展望2022:Android 开发最新技术动向
|
4月前
|
XML Java Android开发
Android App手势冲突处理中上下左右滑动的处理以及侧滑边缘菜单的讲解及实战(附源码 可直接使用)
Android App手势冲突处理中上下左右滑动的处理以及侧滑边缘菜单的讲解及实战(附源码 可直接使用)
65 0