Android携程高级用法,Android真正仿携程首页view实现

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

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

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

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

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

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

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

运行效果:

0818b9ca8b590ca3270a3433284dd417.png

缩放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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值