android ScrollView实现下拉放大头部图片

前言

之前做项目的时候,需要实现类似微博个人主页的ScrollView效果,就是到顶部时继续下拉会放大顶部的图片。然后在网上找了一篇相关的实现,效果非常好,代码也很简洁易懂。(传送门: 自定义scrollView实现顶部图片下拉放大),那么我这里就只是在其基础上修改了一点点而已,比如在代码中控制图片居中、增加动态设置放大的控件、使用自定义的最大放大倍数等,都是很简单的修改,还添加了滑动的监听回调(项目需要)。

效果如下:

思路

老样子,我们先来说下思路,比起代码,思路才是最重要的。具体步骤如下:
1. 获得要放大的控件,并获得其宽高;
2. 在顶部时继续往下拉,通过LayoutParams改变控件的宽高;
3. 手指抬起时初始化各项参数,通过属性动画回弹控件。

实现

直接看代码

public class HeadZoomScrollView extends ScrollView {

 public HeadZoomScrollView(Context context) {
  super(context);
 }

 public HeadZoomScrollView(Context context, AttributeSet attrs) {
  super(context, attrs);
 }

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

 // 用于记录下拉位置
 private float y = 0f;
 // zoomView原本的宽高
 private int zoomViewWidth = 0;
 private int zoomViewHeight = 0;

 // 是否正在放大
 private boolean mScaling = false;

 // 放大的view,默认为第一个子view
 private View zoomView;
 public void setZoomView(View zoomView) {
  this.zoomView = zoomView;
 }

 // 滑动放大系数,系数越大,滑动时放大程度越大
 private float mScaleRatio = 0.4f;
 public void setmScaleRatio(float mScaleRatio) {
  this.mScaleRatio = mScaleRatio;
 }

 // 最大的放大倍数
 private float mScaleTimes = 2f;
 public void setmScaleTimes(int mScaleTimes) {
  this.mScaleTimes = mScaleTimes;
 }

 // 回弹时间系数,系数越小,回弹越快
 private float mReplyRatio = 0.5f;
 public void setmReplyRatio(float mReplyRatio) {
  this.mReplyRatio = mReplyRatio;
 }

 @Override
 protected void onFinishInflate() {
  super.onFinishInflate();
//  不可过度滚动,否则上移后下拉会出现部分空白的情况
  setOverScrollMode(OVER_SCROLL_NEVER);
//  获得默认第一个view
  if (getChildAt(0) != null && getChildAt(0) instanceof ViewGroup && zoomView == null) {
   ViewGroup vg = (ViewGroup) getChildAt(0);
   if (vg.getChildCount() > 0) {
    zoomView = vg.getChildAt(0);
   }
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent ev) {
  if (zoomViewWidth <= 0 || zoomViewHeight <=0) {
   zoomViewWidth = zoomView.getMeasuredWidth();
   zoomViewHeight = zoomView.getMeasuredHeight();
  }
  if (zoomView == null || zoomViewWidth <= 0 || zoomViewHeight <= 0) {
   return super.onTouchEvent(ev);
  }
  switch (ev.getAction()) {
   case MotionEvent.ACTION_MOVE:
    if (!mScaling) {
     if (getScrollY() == 0) {
      y = ev.getY();//滑动到顶部时,记录位置
     } else {
      break;
     }
    }
    int distance = (int) ((ev.getY() - y)*mScaleRatio);
    if (distance < 0) break;//若往下滑动
    mScaling = true;
    setZoom(distance);
    return true;
   case MotionEvent.ACTION_UP:
    mScaling = false;
    replyView();
    break;
  }
  return super.onTouchEvent(ev);
 }

 /**放大view*/
 private void setZoom(float s) {
  float scaleTimes = (float) ((zoomViewWidth+s)/(zoomViewWidth*1.0));
//  如超过最大放大倍数,直接返回
  if (scaleTimes > mScaleTimes) return;

  ViewGroup.LayoutParams layoutParams = zoomView.getLayoutParams();
  layoutParams.width = (int) (zoomViewWidth + s);
  layoutParams.height = (int)(zoomViewHeight*((zoomViewWidth+s)/zoomViewWidth));
//  设置控件水平居中
  ((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width - zoomViewWidth) / 2, 0, 0, 0);
  zoomView.setLayoutParams(layoutParams);
 }

 /**回弹*/
 private void replyView() {
  final float distance = zoomView.getMeasuredWidth() - zoomViewWidth;
  // 设置动画
  ValueAnimator anim = ObjectAnimator.ofFloat(distance, 0.0F).setDuration((long) (distance * mReplyRatio));
  anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    setZoom((Float) animation.getAnimatedValue());
   }
  });
  anim.start();
 }

 @Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
  super.onScrollChanged(l, t, oldl, oldt);
  if (onScrollListener!=null) onScrollListener.onScroll(l,t,oldl,oldt);
 }

 private OnScrollListener onScrollListener;
 public void setOnScrollListener(OnScrollListener onScrollListener) {
  this.onScrollListener = onScrollListener;
 }

 /**滑动监听*/
 public interface OnScrollListener{
  void onScroll(int scrollX,int scrollY,int oldScrollX, int oldScrollY);
 }

}

可以看到,在onTouchEvent方法中,先判断当前是否为放大状态,不是的话就在顶部的时候记录触摸事件的位置,当然这个写在ACTION_DOWN事件中也是可以的,若不在顶部,则不处理。

之后计算滑动的距离,若是往下滑动,则不处理,需要注意的是这个距离是指当前位置与最开始的ACTION_DOWN动作的距离,因此当这个距离小于0的时候,便是”没放大&&往下滑”,这个时候应该滑动的是ScrollView,恩,没毛病。当距离不小于0的时候,开始放大控件,可以看到调用了setZoom方法,注意,在这里其实控件的下拉放大、上拉恢复都做了, 回弹其实也是调用这个方法。

抬手的时候回弹,这个不需要说了。

代码整体来说比较简单,要是你需要其他实现,也可以很方便地加上,比如我们要放大图片的时候像微博一样,旋转外部的菊花,放手的时候刷新数据怎么办?你完全可以在
onTouchEvent中增加回调接口,然后在外部实现具体逻辑就可以了。

使用

直接像普通的ScollView样使用就可以了,这个就不累赘了。

源码:下载地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android DragImageView实现下拉拖动图片放大效果

    DragImageView下拉拖动图片放大,先上图: 主要的类:继承了RelativeLayout,再在RelativeLayout里面添加ImageView,通过Touch事件来改变ImageView的缩放,缩放时计算scale,使其在手指移动到屏幕底部时,图片底部也刚好到达屏幕底部,手指松开时,图片逐步回弹. package com.example.dragimagescale; import android.annotation.SuppressLint; import android.a

  • Android开发重写Animation实现下拉图片后弹射回去效果示例

    本文实例讲述了Android开发重写Animation实现下拉图片后弹射回去效果.分享给大家供大家参考,具体如下: 1. 解析: 1)interpolatedTime指的是平移的变化率(从0到1) 2)mStartHeight 控件开始的高度 3)endHeight 控件竖直移动后的高度 4)mImageView.requestLayout(); 图片在改变高度后填充布局并固定 5)ValueUtil.evalute(interpolatedTime, mStartHeight, mEndHei

  • Android仿QQ好友详情页下拉顶部图片缩放效果

    本文实例为大家分享了Android下拉顶部图片缩放效果展示的具体代码,供大家参考,具体内容如下 效果图 效果分析 1 向下滑动,头部的图片随着手指滑动不断变大 2 向上滑动,不断的向上移动图片,直到图片不可见 3 当顶部图片不可见时,向上滑动,滑动ListView 实现思路 1 由于这个View分上下两部分,垂直排列,可以通过继承LinearLayout实现::自定义一个DragImageView,该View继承LinearLayout public DragImageView(Context

  • Android自定义scrollView实现顶部图片下拉放大

    本文实例为大家分享了scrollView实现顶部图片下拉放大的具体代码,供大家参考,具体内容如下 之前的scrollView顶部图片下拉放大在之后的项目用到了几次,但没次都写在Activity中很麻烦,也不方便复用.这几天有空,所以重新使用自定义scrollView的方法实现这个效果.原理和之前的基本是一致的,所以也不多说了,直接上代码. package com.example.myapplication.dropzoom; import android.animation.ObjectAnim

  • android ScrollView实现下拉放大头部图片

    前言 之前做项目的时候,需要实现类似微博个人主页的ScrollView效果,就是到顶部时继续下拉会放大顶部的图片.然后在网上找了一篇相关的实现,效果非常好,代码也很简洁易懂.(传送门: 自定义scrollView实现顶部图片下拉放大),那么我这里就只是在其基础上修改了一点点而已,比如在代码中控制图片居中.增加动态设置放大的控件.使用自定义的最大放大倍数等,都是很简单的修改,还添加了滑动的监听回调(项目需要). 效果如下: 思路 老样子,我们先来说下思路,比起代码,思路才是最重要的.具体步骤如下:

  • Android简洁的下拉放大刷新效果示例

    序言 国庆放假过后眼看一年又要过完了,年初指望着已经有一年的经验本以为自己不是刚出校的学生以为翅膀已经硬了,打算辞职换新工作,一面试才发现自己就是个垃圾,什么oninterceptEvent,dispatchTouchEvent ,Aysnctask都不会.做了一年的项目也是用的Xutils2.6版本 还有一堆不常用不好的不主流不时尚的框架,技术也没任何长进.还好公司真的轻松(所以也学不到任何东西)可以趁闲下来的时间多学点东西.于是写了个简单但也有需求的控件练练手. 首先先看效果图吧 这个是li

  • Android ScrollView实现下拉弹回动画效果

    这里设计一个自定义View,继承了ScrollView,实现可以下拉里面的内容,松手后画面弹回,这个自定义的View可以当做ScrollView来使用. 一般设计时的应用效果: 一.自定义View的设计代码 package com.lwz.mathbox.weight; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.vie

  • Android实现下拉放大图片松手自动反弹效果

    本文实例为大家分享了Android实现下拉放大图片松手自动反弹的具体代码,供大家参考,具体内容如下 直接看效果: 下面就是代码 HeadZoomScrollView类 import android.animation.ValueAnimator; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; i

  • 解决iOS11图片下拉放大出现信号栏白条的bug问题

    废话不多说了,具体解决方法如下所示: if(@available(iOS11.0, *)) { self.tableView.contentInsetAdjustmentBehavior=UIScrollViewContentInsetAdjustmentNever; }else{ // Fallback on earlier versions self.automaticallyAdjustsScrollViewInsets=NO; } 项目中很多下拉图片放大的效果,使用上面官方给出的iOS1

  • 一个方法搞定iOS下拉放大及上推缩小

    下面这种效果在ios应用中很常见: 实现思路: 1、创建头部的视图和tableview,需要注意的是tableview要设置contentInset,contentInsent 的顶部要和头部视图的背景图的高度一样,否则会有空隙(或是有遮挡). myTableView.contentInset = UIEdgeInsetsMake(headRect.size.height-navHeight-navHeight, 0, 0, 0); 2、对头部视图的背景图片的尺寸进行处理,当然,你也可以直接找一

  • Android自定义控件ListView下拉刷新的代码

    ListView在实际实用中,一般都会有下新刷新和上拉加载的动态效果,今天要学的就是如何自定义带下拉刷新的ListView. 原理解析:一般将有下拉刷新的listview分成四种不同的状态来进行不同的显示效果. 1.完成状态done:listview正常显示状态 2.下拉状态pull:listview正在下拉时的状态 3.释放状态release:listview下拉后松开的状态 4.更新状态refreshing:listview下拉后加载数据时的状态 实现步骤: 自定义CustomListVie

  • Android背景图下拉回弹效果实例

    目录 Android实现背景图下拉回弹效果 效果 实现 总结 Android实现背景图下拉回弹效果 增加设置不横向拉伸时增加回弹效果 增加切换横屏时可滑动效果 效果 实现 public class HeadZoomScrollView extends NestedScrollView { public HeadZoomScrollView(Context context) { super(context); } public HeadZoomScrollView(Context context,

  • Android仿美团下拉菜单(商品选购)实例代码

    美团电商应用平台大家使用非常频繁,下面小编通过本文给大家介绍电商应用平台中常用的选择类别下拉列表的实现.先给大家展示下效果图: 一.下拉列表的实现 其实实现方法有很多,这时实现的也没有什么技术含量,只是总结下自己在项目中的做法,也提供一个思路. 首先是列表的数据,一般数据都是从后台读过来,这里因为没有后台,所以写死在客户端: private void initMenuData() { menuData = new ArrayList<map<string, string=""

随机推荐