android界面特效-----立体的侧滑效果

本人也不是大牛,有讲解的不对的地方,还请指出。

android界面特效-----立体的侧滑效果

效果如上图,在讲解之前,需要感谢specialcyci提供的此控件,对本控件有更好的想法或建议,可以联系[email protected],下面开始讲解实现过程。

本效果主要应用到知识点:fragment,AnimatorSet,ScrollView,GestureDetector

(由于篇幅有限,我就只介绍核心代码了,需要完整代码可以自己clone git@oschina 的项目,路径:http://git.oschina.net/kymjs/KJmusic)

首先:介绍一下本界面的结构,在左侧的MenuList,是一个由ScrollView包裹的LinearLayout;在右侧看到的缩略图效果的content界面,是一个由fragment构成的Activity(立体效果是由一张shadow图片和模糊背景图片产生的)

接着来讲实现方式:

左侧的MenuList,每一个menu item可以通过继承LinearLayout的形式在代码中完成,但是本人更推荐在layout中用xml布局中完成(只有一个imageView一个TextView,很简单)

整个菜单界面(图中的绿色部分)以继承LinearLayout的形式实现,这也是原作的实现方式,当然我更推荐使用xml文件的形式,以下是我对整个menu界面的布局文件(很简单,一个FrameLayout中放一个全屏的imageView做背景,一个ScrollView包裹的LinearLayout做菜单列表,以及一个imageView做阴影部分)

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

    <ImageView
        android:id="@+id/iv_background" />

    <ImageView
        android:id="@+id/iv_shadow" />

    <ScrollView
        android:id="@+id/sv_menu" >

        <LinearLayout
            android:id="@+id/layout_menu" >
        </LinearLayout>
    </ScrollView>

</FrameLayout>

紧接着是本效果的两个重点动画和手势:

我们需要设置两个动画分别用来作为content的显示和收缩

可以通过调用AnimatorSet类对象的playTogether()方法设置

/**
     * 创建菜单退出的动画效果
     * 
     * @param target
     * @param targetScaleX
     * @param targetScaleY
     * 这里的ViewHelper类是来自nineoldandroids 的jar包
     * 第一个参数是哪个View需要设置本动画(当然是Activity了),第二、三个参数是动画的坐标
     * @return
     */
    private AnimatorSet buildScaleDownAnimation(View target,
            float targetScaleX, float targetScaleY) {
        int pivotX = (int) (getScreenWidth() * 1.5);
        int pivotY = (int) (getScreenHeight() * 0.5);

        ViewHelper.setPivotX(target, pivotX);
        ViewHelper.setPivotY(target, pivotY);
        AnimatorSet scaleDown = new AnimatorSet();
        scaleDown.playTogether(
                ObjectAnimator.ofFloat(target, "scaleX", targetScaleX),
                ObjectAnimator.ofFloat(target, "scaleY", targetScaleY));

        scaleDown.setInterpolator(AnimationUtils.loadInterpolator(activity,
                android.R.anim.decelerate_interpolator));
        scaleDown.setDuration(250);
        return scaleDown;
    }

    /**
     * 创建菜单打开的动画效果
     * 
     * @param target
     * @param targetScaleX
     * @param targetScaleY
     * @return
     */
    private AnimatorSet buildScaleUpAnimation(View target, float targetScaleX,
            float targetScaleY) {
        AnimatorSet scaleUp = new AnimatorSet();
        scaleUp.playTogether(
                ObjectAnimator.ofFloat(target, "scaleX", targetScaleX),
                ObjectAnimator.ofFloat(target, "scaleY", targetScaleY));
        scaleUp.setDuration(250);
        return scaleUp;
    }

对于触摸事件的使用,核心部分是重写onFling()方法

    @Override
    public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent2,
            float v, float v2) {

        if (isInIgnoredView(motionEvent) || isInIgnoredView(motionEvent2))
            return false;

        int distanceX = (int) (motionEvent2.getX() - motionEvent.getX());
        int distanceY = (int) (motionEvent2.getY() - motionEvent.getY());
        int screenWidth = (int) getScreenWidth();

        if (Math.abs(distanceY) > screenWidth * 0.3)
            return false;

        if (Math.abs(distanceX) > screenWidth * 0.3) {
            if (distanceX > 0 && !isOpened) {
                // from left to right;
                openMenu();
            } else if (distanceX < 0 && isOpened) {
                // from right th left;
                closeMenu();
            }
        }

        return false;
    }

主要是对一些控件的计算,isinignoredView()方法会在下面讲。

以上就是这个效果的主要内容,也许你看到这里觉得:这没什么特别的啊。没错,的确,如果只是这样的确没什么好说的,而这个效果复杂的地方在于对于触摸屏事件的冲突解决。

在这个问题,原作是通过对整个菜单内的孩子View设置tag的形式作记录,我认为这种做法不是很好,如果当控件很少的时候,是用tag来标记控件的确是个很方便的方法,但是如果控件多了以后,查找起来就很费力,所以本人推荐创建一个集合private List<View> ignoredViews;来存储不需要处理触摸屏事件的View。

通过判断触摸是否发生在需要屏蔽触摸事件的View上,来执行相应的操作

判断的方法(正是上面提到的isinignoredView()方法):

/**
     * 判断触摸是否发生在 不拦截触摸事件的控件上
     * 
     * @Rect类主要用于表示坐标系中的一块矩形区域
     * @param ev
     * @return
     */
    private boolean isInIgnoredView(MotionEvent ev) {
        Rect rect = new Rect();
        for (View v : ignoredViews) {
            v.getGlobalVisibleRect(rect); // 将view位置保存到rect中
            if (rect.contains((int) ev.getX(), (int) ev.getY()))
                return true;
        }
        return false;
    }

最后,也是一个必要点:要作为一个方便使用的控件,需要对其设置一些回调方法,例如:当菜单打开时,菜单关闭时,菜单关闭后,等方法。(对于回调,这里顺便提一点:回调方法就可以看做是:另一个类中的方法,需要一个接口类型的参数,而这个接口类型的参数会在某种特定情况下,被这个接口的实现类调用)

 public interface OnMenuListener {

        /**
         * 这个方法调用完成后将调用打开菜单的动画
         */
        public void openMenu();

        /**
         * 这个方法调用完成后将调用关闭菜单的动画
         */
        public void closeMenu();
    }

至此,在此感谢specialcyci提供的此控件效果,本效果Demo以及项目完整源码在git@china中可以搜索到,这里就不细说了。

你可能感兴趣的:(android,侧滑效果,androidUI)