Android真正仿携程首页view实现

原创 2016年08月30日 23:02:41

一 需求:实现view的点击缩放效果,类似于携程首页。

二 需求分析:对于单纯的view的缩放还是比较简单的,我们使用单纯的android缩放动画就可以实现。但是按照携程首页的view来做的话,里面是有很多细节是我们需要处理的。  

     1 对于一张图片,当我们按下然后左右滑动时它应该仍然处于缩放状态,直到我们的手指脱离开view的边界才回到初始状态。

     2 如果说我们的view的父控件是scrollview的话,这里就需要用到android中事件分发的相关知识了。

        当我们按下view时,需要view来处理接下来的事件,但如果我们是向上或者向下滑动的话,当滑出一小段距离时,我们需要把view重置为

        初始状态,同时把事件交给scrollview来处理使其可以进行上下滑动。

三 说了这么多,相信大家还是有点摸不着头脑的,没关系,我们先来张屏幕截图,然后我们直接贴出源码。

运行效果:


缩放view源码:

package com.example.asiatravel.ctriphomescaleview.view;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;

/**
 * Created by kuangxiaoguo on 16/8/30.
 */
public class CTripHomeScaleView extends ImageView {

    /**
     * 动画持续时长
     */
    private static final int DURATION = 100;
    /**
     * 快速点击的时间间隔
     */
    private static final int TIME_DELAY = 500;
    /**
     * 滑动最小距离
     */
    private static final int MIN_MOVE_DPI = 10;
    /**
     * 缩放的scale
     */
    private static final float SMALL_SCALE = 0.95f;
    /**
     * 初始scale
     */
    private static final float ONE_SCALE = 1f;
    /**
     * 判断缩小动画有没有执行过
     */
    private boolean hasDoneAnimation;
    /**
     * 点击事件监听
     */
    private OnClickListener listener;
    /**
     * 开始动画
     */
    private AnimatorSet beginAnimatorSet;
    /**
     * scale返回动画
     */
    private AnimatorSet backAnimatorSet;
    private int downX;
    private int downY;
    private long lastClickTime;

    public CTripHomeScaleView(Context context) {
        this(context, null);
    }

    public CTripHomeScaleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CTripHomeScaleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAnimation();
    }

    /**
     * Init scale animation
     */
    private void initAnimation() {
        ObjectAnimator beginXAnimation = ObjectAnimator.ofFloat(this, "scaleX", ONE_SCALE, SMALL_SCALE).setDuration(DURATION);
        beginXAnimation.setInterpolator(new LinearInterpolator());
        ObjectAnimator beginYAnimation = ObjectAnimator.ofFloat(this, "scaleY", ONE_SCALE, SMALL_SCALE).setDuration(DURATION);
        beginYAnimation.setInterpolator(new LinearInterpolator());
        ObjectAnimator backXAnimation = ObjectAnimator.ofFloat(this, "scaleX", SMALL_SCALE, ONE_SCALE).setDuration(DURATION);
        backXAnimation.setInterpolator(new LinearInterpolator());
        ObjectAnimator backYAnimation = ObjectAnimator.ofFloat(this, "scaleY", SMALL_SCALE, ONE_SCALE).setDuration(DURATION);
        backYAnimation.setInterpolator(new LinearInterpolator());
        beginAnimatorSet = new AnimatorSet();
        beginAnimatorSet.play(beginXAnimation).with(beginYAnimation);
        backAnimatorSet = new AnimatorSet();
        backAnimatorSet.play(backXAnimation).with(backYAnimation);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                /**
                 * 判断是不是快速点击
                 */
                if (isFastClick()) {
                    return true;
                }
                /**
                 * 请求父类不要拦截我的事件,意思是让我来处理接下来的滑动或别的事件
                 */
                getParent().requestDisallowInterceptTouchEvent(true);
                downX = (int) event.getX();
                downY = (int) event.getY();
                hasDoneAnimation = false;
                post(new Runnable() {
                    @Override
                    public void run() {
                        beginAnimatorSet.start();
                    }
                });
                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) event.getX();
                int moveY = (int) event.getY();
                int moveDistanceX = Math.abs(moveX) - downX;
                int moveDistanceY = Math.abs(moveY) - downY;
                /**
                 * 这里是判断是向左还是向右滑动,然后用view的宽度计算出一个距离compareWidth,当滑动距离超出compareWidth时,需要执行返回动画.
                 */
                int compareWidth = moveDistanceX > 0 ? getWidth() - downX : downX;
                /**
                 * 第一个条件:判断向上或向下滑动距离大于滑动最小距离
                 * 第二个条件:判断向左或向右的滑动距离是否超出(compareWidth-最小距离)
                 * 第三个条件:判断有没有执行过返回动画并在执行过一次后置为true.
                 */
                if ((Math.abs(moveDistanceY) > dip2px(MIN_MOVE_DPI) || Math.abs(moveDistanceX) >= compareWidth - dip2px(MIN_MOVE_DPI)) && !hasDoneAnimation) {
                    /**
                     * 一 只要满足上述条件,就代表用户不是点击view,而是执行了滑动操作,这个时候我们就需要父类以及我们的最上层的控件来
                     * 拦截我们的事件,让最外层控件处理接下来的事件,比如scrollview的滑动.
                     * 二 因为我们执行了滑动操作,所以要执行view的返回动画
                     */
                    getParent().requestDisallowInterceptTouchEvent(false);
                    hasDoneAnimation = true;
                    post(new Runnable() {
                        @Override
                        public void run() {
                            backAnimatorSet.start();
                        }
                    });
                }
                break;
            case MotionEvent.ACTION_UP:
                /**
                 * 这里如果我们是单纯的点击事件就会执行
                 */
                if (!hasDoneAnimation) {
                    hasDoneAnimation = true;
                    post(new Runnable() {
                        @Override
                        public void run() {
                            backAnimatorSet.start();
                        }
                    });
                    post(new Runnable() {
                        @Override
                        public void run() {
                            /**
                             * 接口回调点击事件
                             */
                            if (listener != null) {
                                listener.onClick(CTripHomeScaleView.this);
                            }
                        }
                    });
                }
                break;
        }
        return true;
    }

    public void setOnClickListener(OnClickListener l) {
        listener = l;
    }

    public interface OnClickListener {
        void onClick(View v);
    }

    /**
     * Make dp to px
     *
     * @param dipValue dp you need to change
     * @return Get px according to your dp value.
     */
    public int dip2px(float dipValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    /**
     * Judge is fast click event.
     *
     * @return Is fast click or not.
     */
    public boolean isFastClick() {
        long time = System.currentTimeMillis();
        long timeD = time - lastClickTime;
        if (timeD < TIME_DELAY) {
            return true;
        } else {
            lastClickTime = time;
            return false;
        }
    }
}
总结:代码量不多,主要的逻辑是在处理view的onTouch事件时,注释在代码里写的还算清晰,所以这里就不在做赘述了,不懂的童鞋可以在下面留言,或者可以发邮件:kuangxiaoguo@163.com。
希望我的文章可以帮到大家,最后附上github源码地址:https://github.com/kuangxiaoguo0123/ctripHomeScaleView
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

android自定义View之仿携程首页点击缩放ImageView

最近下了个携程App,点开首页看,注意到其按钮在点击的时候并不是我们经常看到的变色效果,而是先收缩,放开时,再回到原来的大小,感觉这个效果虽然小,但是感觉非常新颖,于是决定,模仿一下这个小效果,先看一...

Android 仿去哪儿携程地址互换效果

昨天朋友项目中有个需求让我帮忙看看怎么搞,就跟去哪儿携程买机票时点中间按钮互换出发地和目的地的效果,当时一看觉得挺简单,用补间动画,在动画完成时设置给两边各textview互换值就好,做出来后发现效果...

jquery仿携程网城市选择插件

效果-------                          ...

Android设计支持库(Android Design Support Library)

在谷歌2015的I/O大会上,谷歌公布了一个新的设计支持库,它里面包含许多材料设计组件,并且这个库支持Android 2.1及其以上版本。这个支持库,包含了以下关键特性: 1、NavigationV...

Android之ViewPager+GridView实现仿美团首页导航栏布局分页效果

用过美团app的小伙伴都应该非常熟悉,美团首页的分类导航栏是作为一个头布局展示在首页上的,并且分类过多的话则可以滑动查看。本篇博客正如题目所说,采用ViewPager+GridView的方式来实现美团...

android 仿首页广告轮播效果

1.我们经常打开一个App会看到有广告图片轮播的效果,首先上效果图 1.我们经常打开一个App会看到有广告图片轮播的效果,首先上效果图 2.实现的过程 1.轮播页面他是一个ViewPager 2...

android 仿去哪儿首页效果

首先上效果图 第一张图是进入该界面的效果,顶部是一个viewpager,下面每个块都是自定义的view HomeButton,第二张图是点击右边第一个方块的效果,点击时方块整体有收缩的效果,...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)