前言
嗨,各位看官好久不见,博文这种东西啊,真的是一个捉摸不定的事情,哈哈哈。今天给大家带来一个商城类App,或者是个人中心需要下拉页面放大headView的工具类,无图无真相。
干货
项目地址:github地址
1.在project的build文件中添加如下:
allprojects {
repositories {
jcenter()
maven { url 'https://jitpack.io' }
}
}
2.然后在app的build文件依赖即可
compile 'com.github.Blincheng:PullDownEnlargeUtilDemo:v1.2'
3.使用非常简单一步集成
new PullDownEnlargeAnimUtil(findViewById(R.id.scrollView),findViewById(R.id.image));
实现步骤
总的来说是非常简单的,只要稍微有点数学计算能力~哈哈哈
1.通过事件监听来获取放大的指令.如果是顶部,继续下拉,那就放大该放大的View
2.松手后的回弹动画处理
3.简单封装,直接可以使用
4.使用干货
1.监听事件
这边我是通过setOnTouchListener(…);来监听滑动事件的,为啥不用onScroll…啥啥啥呢?因为后边要封装,当然是能兼容所有的View了,对吧!
看看代码:
@Override
public boolean onTouch(View v, MotionEvent event) {
initView();
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
//手指离开后恢复图片
isScaling = false;
replayAnim();
break;
case MotionEvent.ACTION_MOVE:
if (!isScaling) {
if (parentView.getScrollY() == 0) {
//滚动到顶部时需要记录当前位置
mFirstPosition = event.getY();
} else {
break;
}
}
int distance = (int) ((event.getY() - mFirstPosition) * 0.3); // 这边添加了一个对应滚动的系数,可以自由调节
if (distance < 0) {
break;
}
// 处理放大
isScaling = true;
ViewGroup.LayoutParams lp = childView.getLayoutParams();
lp.height = (int) (height + distance*MAGNIFICATION_Y);
lp.width = (int) (width+ distance*MAGNIFICATION_X);
childView.setLayoutParams(lp);
childView.scrollTo((int) ((distance/2)*MAGNIFICATION_X),0);
nowDistance = distance;
return true;
}
return false;
}
先不看其他的代码哈,先parentView.getScrollY()去获取当前是都滚动到顶部,如果不是,那么就直接呵呵,如果事,就记录当前第一次的位置(这个位置有点重要,然后继续往下走)。之后就是计算手指滑动的距离,计算差值,更改要放大缩小的子View。还有一个重点就是我们需要的是居中放大,如果子View的外层中心是水平居中,其实不用做处理,如果不是水平居中,那么其实放大的中心点是左上角,那么同时需要我们将View向左平移二分之一的放大量,自己体会体会哈。然后如果手指弹起,那么走replayAnim();并且设置放大状态为false。
2.松手回弹动画
//松手后的回弹动画
public void replayAnim() {
final ViewGroup.LayoutParams lp = childView.getLayoutParams();
final float w = childView.getLayoutParams().width;// 图片当前宽度
final float h = childView.getLayoutParams().height;
final float newW = width;// 图片原宽度
final float newH = height;
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0.0F, 1.0F).setDuration(200);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float cVal = (Float) animation.getAnimatedValue();
lp.width = (int) (w - (w - newW) * cVal);
lp.height = (int) (h - (h - newH) * cVal);
childView.setLayoutParams(lp);
childView.scrollTo((int) ((int) (nowDistance*(1-cVal)/2)*MAGNIFICATION_X),0);
}
});
valueAnimator.start();
}
看看代码,反向处理水平位移,看看childView.scrollTo((int) ((int) (nowDistance*(1-cVal)/2)*MAGNIFICATION_X),0);这边才是算法的精妙,数学的重要性,哈哈哈,具体叫啥来着,倒数吗~好吧,就当我乱说。缩小就不说了,简单。
3.简单的封装
最后就是封装一下,变成一个干货,可以直接拿来使用。嗯,对的,就应该是这样。小二~上全部代码!
public class PullDownEnlargeAnimUtil {
/**
* 要放大的子View
* */
private View childView;
/**
* 监听滚动事件的父View
* */
private View parentView;
/**
* X方向放大的倍率
* */
private float MAGNIFICATION_X = 1.0f;
/**
* Y方向放大的倍率
* */
private float MAGNIFICATION_Y = 1.0f;
/**
* 是否正在放大
* */
private boolean isScaling;
/**
* 记录首次按下位置
* */
private float mFirstPosition = 0;
/**
* 下拉偏移量(主要用来逆向位移)
* */
private int nowDistance;
/**
* 要放大控件的初始宽高,第一次初始化在第一次走onTouch()的时候
* */
private int width = 0;
private int height = 0;
public PullDownEnlargeAnimUtil(View parentView,View childView){
this.childView = childView;
this.parentView = parentView;
initEvent();
}
private void initEvent(){
parentView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
initView();
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
//手指离开后恢复图片
isScaling = false;
replayAnim();
break;
case MotionEvent.ACTION_MOVE:
if (!isScaling) {
if (parentView.getScrollY() == 0) {
//滚动到顶部时需要记录当前位置
mFirstPosition = event.getY();
} else {
break;
}
}
int distance = (int) ((event.getY() - mFirstPosition) * 0.3); // 这边添加了一个对应滚动的系数,可以自由调节
if (distance < 0) {
break;
}
// 处理放大
isScaling = true;
ViewGroup.LayoutParams lp = childView.getLayoutParams();
lp.height = (int) (height + distance*MAGNIFICATION_Y);
lp.width = (int) (width+ distance*MAGNIFICATION_X);
childView.setLayoutParams(lp);
childView.scrollTo((int) ((distance/2)*MAGNIFICATION_X),0);
nowDistance = distance;
return true;
}
return false;
}
});
}
private void initView(){
if(width == 0||height == 0){
width = childView.getWidth();
height = childView.getHeight();
}
}
//松手后的回弹动画
public void replayAnim() {
final ViewGroup.LayoutParams lp = childView.getLayoutParams();
final float w = childView.getLayoutParams().width;// 图片当前宽度
final float h = childView.getLayoutParams().height;
final float newW = width;// 图片原宽度
final float newH = height;
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0.0F, 1.0F).setDuration(200);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float cVal = (Float) animation.getAnimatedValue();
lp.width = (int) (w - (w - newW) * cVal);
lp.height = (int) (h - (h - newH) * cVal);
childView.setLayoutParams(lp);
childView.scrollTo((int) ((int) (nowDistance*(1-cVal)/2)*MAGNIFICATION_X),0);
}
});
valueAnimator.start();
}
}
使用干货
那么封装好了,怎么用呢?
一行代码解决,如下:
//第一个参数是滚动布局,其实就是提供滑动监听的依赖布局,其实并不一定是福布局。
//第二个参数是需要放大的View,理论上可以是任何View,可以在任何布局里面。
new PullDownEnlargeAnimUtil(parentView,childView);
总结
东西整体来说不难的,但是要自己从0开始写,那也还是需要一些时间和一些思考的,有些东西还是要调一调,折腾一下才能出来的,虽然东西不难,就是需要思路。本次项目代码就不上传到github了,就一个类,已经贴在上面,大家如果有需要直接拷贝就是了。如果有什么问题欢迎大家留言或e我哦,随时欢迎,下次再见。