Android 自定义SlidingMenu 实现QQ5.0侧滑菜单动画效果

我们知道SlidingMenu原生只支持侧滑菜单滑动时的动画效果(自带的Demo中有CustomScaleAnimation,CustomZoomAnimation等),而QQ5.0的侧滑时前面的主页面也有一个缩小的动画效果,那我们是不是可以在SlidingMenu的基础上扩展一下,增加一个和侧滑菜单相同的动画机制呢?我们先来看一下源码里侧滑菜单的动画效果是怎么实现的~~

1.原理分析

1.SlidingMenu源码中有两个类叫做CustomViewAbove和CustomViewBehind,分别对应主页面和侧滑菜单

2.通过阅读SlidingMenu源码发现MenuView对应的实现类叫CustomViewBehind,里面有一个CanvasTransformer的接口对象

<span style="font-family:Microsoft YaHei;font-size:14px;">private CanvasTransformer mTransformer;</span>

定义如下

<span style="font-family:Microsoft YaHei;font-size:14px;">	/**
	 * The Interface CanvasTransformer.
	 */
	public interface CanvasTransformer {

		/**
		 * Transform canvas.
		 *
		 * @param canvas the canvas
		 * @param percentOpen the percent open
		 */
		public void transformCanvas(Canvas canvas, float percentOpen);
	}</span>

他只是把Canvas对象,以及侧滑的进度值percentOpen(0.0-1.0)传递给实现类,由实现类自己定义动画效果。

在CustomViewBehind中只有三处调用:

<span style="font-family:Microsoft YaHei;font-size:14px;">	@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);
	}</span>

<span style="font-family:Microsoft YaHei;font-size:14px;">	@Override
	public void scrollTo(int x, int y) {
		super.scrollTo(x, y);
		if (mTransformer != null)
			invalidate();
	}</span>

<span style="font-family:Microsoft YaHei;font-size:14px;">	public void setCanvasTransformer(CanvasTransformer t) {
		mTransformer = t;
	}
</span>

以发现实际就是在画自己的时候(dispatchDraw)加了一个canvas的动画效果。
好,原理清楚了,那我们来修改一实现

2.实现

第一步,修改源码

先将CustomViewBehind中mTransformer以及相关的三个方法Copy到CustomViewAbove中去。 (scrollTo中的invalidate调用我没加,因为觉得滑动时页面肯定会重绘,不需要再手动再调用一遍了,目前测试没问题,不放心的同学也可以加上。。。)
然后相应的,在SlidingMenu中加上设置CanvasTransformer的方法
	/**
	 * Sets the foreground canvas transformer.
	 * 
	 * @param t the new foreground canvas transformer
	 */
	public void setAboveCanvasTransformer(CanvasTransformer t){
		mViewAbove.setCanvasTransformer(t);
	}

第二步,调整动画效果

<span style="white-space:pre">		</span>SlidingMenu sm = getSlidingMenu();
		sm.setBehindOffset(200);//menu滑动到距离屏幕右边200个像素的位置
		sm.setFadeDegree(0.35f);//menu的渐隐效果系数(0-1)
		sm.setBehindScrollScale(0.25f);//主页面移动1个像素,menu移动0.25个像素
		sm.setAboveCanvasTransformer(new CanvasTransformer() {
			
			@Override
			public void transformCanvas(Canvas canvas, float percentOpen) {
				//percentOpen从0变到1,原图从1倍大小缩小到3/4
				float scale = (float) (1.0 - 0.25 * percentOpen);
				//x,y方向同时缩小,动画的相对中心定在“左中”,这样就不至于缩放的时候屏幕左边出现一条空白。
				canvas.scale(scale, scale, 0, canvas.getHeight() / 2);
			}
		});
		
		sm.setBehindCanvasTransformer(new CanvasTransformer() {
			
			@Override
			public void transformCanvas(Canvas canvas, float percentOpen) {
				//原图从3/4增加到1倍大小
				float scale = (float) (0.75 + 0.25 * percentOpen);
				//x坐标先向屏幕左边移动1/4的视图宽度,然后再慢慢移动到0,这样来实现从屏幕左边移动进屏幕的效果
				canvas.translate(-canvas.getWidth()/4 + percentOpen * canvas.getWidth()/4, 0);
				//x,y方向同时放大,动画的相对中心定在“右中”
				canvas.scale(scale, scale, canvas.getWidth(), canvas.getHeight() / 2);
				
			}
		});


源码:

1.MainActivity.java

package com.example.slidemenudemo;

import android.graphics.Canvas;
import android.os.Bundle;
import android.util.TypedValue;

import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu.CanvasTransformer;
import com.jeremyfeinstein.slidingmenu.lib.app.SlidingFragmentActivity;


public class MainActivity extends SlidingFragmentActivity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		setBehindContentView(R.layout.menu_frame);
		setContentView(R.layout.content_frame);
		
		if (savedInstanceState == null) {
			getSupportFragmentManager().beginTransaction()
			.replace(R.id.frame, new SampleListFragment())
			.replace(R.id.content_frame, new SampleListFragment()).commit();
		}
		
		SlidingMenu sm = getSlidingMenu();
		sm.setBehindOffset(200);//menu滑动到距离屏幕右边200个像素的位置
		sm.setFadeDegree(0.35f);//menu的渐隐效果系数(0-1)
		sm.setBehindScrollScale(0.25f);//主页面移动1个像素,menu移动0.25个像素
		sm.setAboveCanvasTransformer(new CanvasTransformer() {
			
			@Override
			public void transformCanvas(Canvas canvas, float percentOpen) {
				//percentOpen从0变到1,原图从1倍大小缩小到3/4
				float scale = (float) (1.0 - 0.25 * percentOpen);
				//x,y方向同时缩小,动画的相对中心定在“左中”,这样就不至于缩放的时候屏幕左边出现一条空白。
				canvas.scale(scale, scale, 0, canvas.getHeight() / 2);
			}
		});
		
		sm.setBehindCanvasTransformer(new CanvasTransformer() {
			
			@Override
			public void transformCanvas(Canvas canvas, float percentOpen) {
				//原图从3/4增加到1倍大小
				float scale = (float) (0.75 + 0.25 * percentOpen);
				//x坐标先向屏幕左边移动1/4的视图宽度,然后再慢慢移动到0,这样来实现从屏幕左边移动进屏幕的效果
				canvas.translate(-canvas.getWidth()/4 + percentOpen * canvas.getWidth()/4, 0);
				//x,y方向同时放大,动画的相对中心定在“右中”
				canvas.scale(scale, scale, canvas.getWidth(), canvas.getHeight() / 2);
				
			}
		});
		sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
		
	}

}

2. SampleListFragment.java

package com.example.slidemenudemo;

import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.widget.ArrayAdapter;

public class SampleListFragment extends ListFragment {

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

		ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity().getApplicationContext(), android.R.layout.simple_list_item_1);

		for (int i = 0; i < 20; i++) {
			adapter.add("item " + i);
		}
		setListAdapter(adapter);
	}

}


资源文件

1.menu_fragment.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

2.content_frame.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />




  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值