这个效果其实就是QQ主界面弹出“我”的滑动效果,类似于一个slideMenu的变种版。第一次看的时候老板觉得这个效果很不错,于是就让我们实现一下了。文章的主体结构就是:
讲述一下本效果的主要功能;
实现的思路;
代码展示;
代码下载;
主要功能
大概的实现效果请见下图:
通过上面的图,我们来说下这个效果的主要功能:
1.横向滑动时(有滑动边界,比如距左边20dp滑动有效,多了就不算是有效滑动),可以将菜单滑出来。
2.在菜单关闭状态下,点击”点击打开”文字,直接弹出菜单。
3.在菜单打开状态下,点击右边的布局,菜单收回。
4.在菜单打开状态下,向右滑动,菜单收回。
5.在菜单打开状态下,点击返回键,菜单收回。
实现思路
通过观察QQ的设置动画,发现其实这个动画只是主界面和”我“的界面在同时”播放“一段动画。只不过两个动画的行为不同,而这个动画通过左上角的按钮触发,而滑动的时候,是这段动画的分解动作。而图形的绘制方面,可以采用一个ViewGroup里放置两个子ViewGroup分别用来当作”主界面”和“我”的界面来使用。
本demo采用的方法是自定义一个ViewGroup,让他继承FrameLayout(与效果最契合的layout),然后给这个ViewGroup定义两个子View,leftView和rightView。然后左右两边分别定义一套动画逻辑,让他们在事件处理的时候可以“播放”这些动画。
给这个View定义两个可以让用户自己定义的属性,1个是leftView的宽度,这样等于定义了用户可以滑动的距离(因为左边的视图完全显示了,滑动也就结束了)。另一个是滑动的边界值,用来控制滑动事件的范围。
代码展示
下面来说说代码的具体实现。首先自定义了一个视图,起名为SlideView,它继承于FrameLayout,定义一些必要的成员变量
public class SlideView extends FrameLayout {
private View leftView;// 左边视图的内容
private View rightView;// 右边视图的内容
private int width_left;// 自界面的宽度,也代表最大可滑动的距离
private float offsetX = 0.0f;// 当前视图的偏移量(X)
private final int OPEN = 1;// 当前状态,打开
private final int CLOSE = 0;// 当前状态,关闭
private int state = CLOSE;// 当前视图的状态
private int boundary;// 可以滑动的边缘
...
}
我们需要把这两个视图添加进去并且进行初始化,可以使用xml的方式也可以在代码里添加,这里选择了在使用时在代码里添加,,并且对两个子视图分别进行了设置:
public void initView(final View vLeft, final View vRight) {
if (isInit) {
// 已经初始化,没有必要再次进行
return;
}
leftView = vLeft;
rightView = vRight;
setupLeftView();
setupRightView();
SlideView.this.removeAllViews();
SlideView.this.addView(leftView);
SlideView.this.addView(rightView);
}
private void setupLeftView() {
FrameLayout.LayoutParams lps = new FrameLayout.LayoutParams(width_left,
FrameLayout.LayoutParams.MATCH_PARENT);
lps.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
leftView.setLayoutParams(lps);
}
private void setupRightView() {
FrameLayout.LayoutParams lps = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
lps.gravity = Gravity.CENTER;
rightView.setLayoutParams(lps);
}
对于左边和右边的动画,定义了两个方法,这两个方法都是通过当前的进度(0-1)来决定播放到哪里,当传进0的时候,菜单完全关闭,传1,菜单完全打开
/** 进行左边的动画(参数为0.0-1.0),代表当前动画进行的进度 */
private void doLeftAnimation(float avg) {
leftView.setTranslationX(-width_left / 10 + avg *