Android ListView实现下拉顶部图片变大效果

本文实例为大家分享了Android ListView下拉顶部图片变大的具体代码,供大家参考,具体内容如下

在git上查看牛人的代码,发现是反编译别人的代码,还没加注释,代码也没有完全编译完整,所以这里我做的简单的注释,仅供学习。

变量说明

这里变量包含了:自定义返回动画加速度、自定义动画线程、头部图片view,最后的y坐标,做好的比例,做大的比例等。

private static final String TAG = "PullToZoomListView";

 private static final int INVALID_VALUE = -1;//重置值

 //自定义加速度动画
 private static final Interpolator sInterpolator = new Interpolator() {
  public float getInterpolation(float interpolator) {
   float f = interpolator - 1.0F;
   return 1.0F + f * (f * (f * (f * f)));
  }
 };
 private int mActivePointerId = INVALID_VALUE;//当前手指的Id
 private FrameLayout mHeaderContainer;//头部
 private int mHeaderHeight;//头部图片的高度
 private ImageView mHeaderImage;//头部图片
 float mLastMotionY = INVALID_VALUE;//最后y坐标
 float mLastScale = INVALID_VALUE;//最后的比例
 float mMaxScale = INVALID_VALUE;//最大的比例
 private OnScrollListener mOnScrollListener;//滑动监听
 private ScalingRunnalable mScalingRunnalable;//动画线程
 private int mScreenHeight;//屏幕高度
 private ImageView mShadow;//阴影遮罩

自定义View初始化:设置了头部的头部和遮罩并且设置了监听。

/**
  * 初始化
  * @param paramContext
  */
 private void init(Context paramContext) {
  DisplayMetrics metrics = new DisplayMetrics();
  ((Activity) paramContext).getWindowManager().getDefaultDisplay().getMetrics(metrics);

  this.mScreenHeight = metrics.heightPixels;//屏幕高度赋值
  this.mHeaderContainer = new FrameLayout(paramContext);//头部
  this.mHeaderImage = new ImageView(paramContext);//头部图片
  int screenWidth = metrics.widthPixels;//屏幕宽度

  //设置头部View的样式 设置屏幕宽度,最大样式高度为屏幕高度的9/16
  setHeaderViewSize(screenWidth, (int) (9.0F * (screenWidth / 16.0F)));

  this.mShadow = new ImageView(paramContext);//遮罩
  FrameLayout.LayoutParams layoutParams =
    new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
      ViewGroup.LayoutParams.MATCH_PARENT);
  layoutParams.gravity = Gravity.CENTER;
  this.mShadow.setLayoutParams(layoutParams);//设置遮罩样式
  //头部添加View
  this.mHeaderContainer.addView(this.mHeaderImage);
  this.mHeaderContainer.addView(this.mShadow);
  //添加头部
  addHeaderView(this.mHeaderContainer);
  //初始化返回动画
  this.mScalingRunnalable = new ScalingRunnalable();
  //设置监听
  super.setOnScrollListener(this);
 }

开启动画:判断当前的头部布局底部的位置–是否大于图片的初始化高度。

/**
  * 开启动画
  */
 private void endScraling() {
  if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) {
   Log.d(TAG, "this.mScalingRunnalable.startAnimation(200L)");
   this.mScalingRunnalable.startAnimation(200L);
  }
 }

多指触碰时将第0个手指赋值。

/**
  * 多点触碰的时候按下,当第0个有手指抬起,再次有手指按下后,将按下的事件的手指指针作为当前手指指针
  *
  * @param motionEvent
  */
 private void onSecondaryPointerUp(MotionEvent motionEvent) {
  Log.d(TAG, "onSecondaryPointerUp motionEvent.getPointerId(0) = " + motionEvent.getPointerId(0));
  Log.d(TAG, "onSecondaryPointerUp this.mActivePointerId = " + this.mActivePointerId);
  if (motionEvent.getPointerId(0) == this.mActivePointerId) {
   this.mLastMotionY = motionEvent.getY(0);
   this.mActivePointerId = motionEvent.getPointerId(0);
  }
  Log.d(TAG, "onSecondaryPointerUp mLastMotionY = " + mLastMotionY);
  Log.d(TAG, "onSecondaryPointerUp mActivePointerId = " + mActivePointerId);
 }

重置所有的数据

/**
 * 重置所有数据
*/
 private void reset() {
  this.mActivePointerId = INVALID_VALUE;
  this.mLastMotionY = INVALID_VALUE;
  this.mMaxScale = INVALID_VALUE;
  this.mLastScale = INVALID_VALUE;
 }

向上滚动时修改布局样式

@Override
 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  Log.d(TAG, "onScroll");

  float bottomSpacing = this.mHeaderHeight - this.mHeaderContainer.getBottom();
  Log.d(TAG, "onScroll bottomSpacing = " + bottomSpacing);

  if ((bottomSpacing > 0.0F) && (bottomSpacing < this.mHeaderHeight)) {//如果是向上滑动
   int toUpScroll = (int) (0.65D * bottomSpacing);
   this.mHeaderImage.scrollTo(0, -toUpScroll);
   Log.d(TAG, "onScroll 向上滑动 toUpScroll = " + toUpScroll);
  } else if (this.mHeaderImage.getScrollY() != 0) {
   Log.d(TAG, "onScroll this.mHeaderImage.getScrollY() = " + this.mHeaderImage.getScrollY());
   this.mHeaderImage.scrollTo(0, 0);
  }
  if (this.mOnScrollListener != null) {
   this.mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
  }
 }

不同事件处理,修改布局样式

@Override
 public boolean onTouchEvent(MotionEvent motionEvent) {
  switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
   case MotionEvent.ACTION_OUTSIDE:
   case MotionEvent.ACTION_DOWN:
    if (!this.mScalingRunnalable.mIsFinished) {
     this.mScalingRunnalable.abortAnimation();
    }
    this.mLastMotionY = motionEvent.getY();
    //获取第一个手指指针的ID
    this.mActivePointerId = motionEvent.getPointerId(0);
    this.mMaxScale = (this.mScreenHeight / this.mHeaderHeight);
    this.mLastScale = (this.mHeaderContainer.getBottom() / this.mHeaderHeight);
    Log.d(TAG, "onTouchEvent ACTION_DOWN mLastMotionY = " + mLastMotionY);
    Log.d(TAG, "onTouchEvent ACTION_DOWN mActivePointerId = " + mActivePointerId);
    Log.d(TAG, "onTouchEvent ACTION_DOWN mMaxScale = " + mMaxScale);
    Log.d(TAG, "onTouchEvent ACTION_DOWN mLastScale = " + mLastScale);
    break;
   case MotionEvent.ACTION_MOVE:
    Log.d(TAG, "onTouchEvent ACTION_MOVE mActivePointerId" + mActivePointerId);
    //获取当前id的手机指针
    int pointer = motionEvent.findPointerIndex(this.mActivePointerId);
    //判断指针不为空
    if (pointer == INVALID_VALUE) {
     Log.e(TAG, "Invalid pointerId=" + this.mActivePointerId + " in onTouchEvent");
    } else {
     //如果开始没有赋值,则需要赋值
     if (this.mLastMotionY == INVALID_VALUE) {
      this.mLastMotionY = motionEvent.getY(pointer);
     }
     if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) {
      //获取头部样式
      ViewGroup.LayoutParams headerParams = this.mHeaderContainer.getLayoutParams();

      float currentScale = ((motionEvent.getY(pointer) - this.mLastMotionY + this.mHeaderContainer.getBottom())
        / this.mHeaderHeight - this.mLastScale)
        / 2.0F + this.mLastScale;
      if ((this.mLastScale <= 1.0D) && (currentScale < this.mLastScale)) {
       //最后比例小于默认并且当前的比例要小于上次的比例,则修改头部的高度
       headerParams.height = this.mHeaderHeight;
       this.mHeaderContainer.setLayoutParams(headerParams);
       return super.onTouchEvent(motionEvent);
      } else {
       //否则,将当前的比例赋值为最后一次的比例
       this.mLastScale = Math.min(Math.max(currentScale, 1.0F), this.mMaxScale);
       headerParams.height = ((int) (this.mHeaderHeight * this.mLastScale));
       //判断修改后的高度小于屏幕的高度
       if (headerParams.height < this.mScreenHeight) {
        this.mHeaderContainer.setLayoutParams(headerParams);
       }
       //记录最后的y坐标
       this.mLastMotionY = motionEvent.getY(pointer);
       return true;
      }
     }
     this.mLastMotionY = motionEvent.getY(pointer);
    }
    break;
   case MotionEvent.ACTION_UP:
    Log.d(TAG, "onTouchEvent ACTION_UP 重置");
    //重置
    reset();
    //当手指起来的时候,结算拉伸,判断是否开启动画
    endScraling();
    break;
   case MotionEvent.ACTION_CANCEL:
    int actionIndex = motionEvent.getActionIndex();//获取当前最上层的指针
    this.mLastMotionY = motionEvent.getY(actionIndex);//获取最后的y坐标
    this.mActivePointerId = motionEvent.getPointerId(actionIndex);//获取最上层指针的手指
    Log.d(TAG, "onTouchEvent ACTION_CANCEL actionIndex = " + actionIndex + " mLastMotionY = " + mLastMotionY + " mActivePointerId = " + mActivePointerId);
    break;
   case MotionEvent.ACTION_POINTER_DOWN:
    //当第二个手指按下或者放开触发这个事件
    onSecondaryPointerUp(motionEvent);
    this.mLastMotionY = motionEvent.getY(motionEvent.findPointerIndex(this.mActivePointerId));
    Log.d(TAG, "onTouchEvent_Po ACTION_POINTER_DOWN mLastMotionY = " + mLastMotionY);
    break;
   case MotionEvent.ACTION_POINTER_UP:
    //当第二个手指按下或者放开
    Log.d(TAG, "onTouchEvent_Po ACTION_POINTER_UP ");
    break;
  }
  return super.onTouchEvent(motionEvent);
 }

向上返回时的动画

/**
  * 向上返回的动画
  */
 class ScalingRunnalable implements Runnable {
  long mDuration;//持续时间
  boolean mIsFinished = true;//是否结束
  float mScale;//比例
  long mStartTime;//开始时间

  ScalingRunnalable() {
  }

  /**
   * 中止动画
   */
  public void abortAnimation() {
   this.mIsFinished = true;
  }

  /**
   * 是否中止
   *
   * @return
   */
  public boolean isFinished() {
   return this.mIsFinished;
  }

  public void run() {
   Log.d(TAG, "ScalingRunnalable mIsFinished = " + this.mIsFinished + " this.mScale = " + this.mScale);
   float currentScale;
   ViewGroup.LayoutParams mHeaderContainerParams;//头部样式
   //判断是否中止和已经滑动超过的默认大小
   if ((!this.mIsFinished) && (this.mScale > 1.0D)) {
    float currentTime = ((float) SystemClock.currentThreadTimeMillis() - (float) this.mStartTime) / (float) this.mDuration;
    currentScale = this.mScale - (this.mScale - 1.0F) * PullToZoomListView.sInterpolator.getInterpolation(currentTime);
    Log.d(TAG, "ScalingRunnalable currentTime = " + currentTime + " currentScale = " + currentScale);

    mHeaderContainerParams = PullToZoomListView.this.mHeaderContainer.getLayoutParams();
    if (currentScale > 1.0F) {
     Log.d(TAG, "ScalingRunnalable currentScale > 1.0 -- 修改头部高度");
     mHeaderContainerParams.height = PullToZoomListView.this.mHeaderHeight;
     mHeaderContainerParams.height = ((int) (currentScale * PullToZoomListView.this.mHeaderHeight));
     PullToZoomListView.this.mHeaderContainer.setLayoutParams(mHeaderContainerParams);
     PullToZoomListView.this.post(this);//循环执行
    } else {
     Log.d(TAG, "ScalingRunnalable currentScale < 1.0 -- 中止");
     this.mIsFinished = true;
    }
   }
  }

  public void startAnimation(long paramLong) {
   Log.d(TAG, "ScalingRunnalable 开始执行动画");
   this.mStartTime = SystemClock.currentThreadTimeMillis();
   this.mDuration = paramLong;
   this.mScale = ((float) (PullToZoomListView.this.mHeaderContainer.getBottom()) / PullToZoomListView.this.mHeaderHeight);
   this.mIsFinished = false;
   Log.d(TAG, "ScalingRunnalable this.mStartTime = " + this.mStartTime);
   Log.d(TAG, "ScalingRunnalable this.mDuration = " + this.mDuration);
   Log.d(TAG, "ScalingRunnalable this.mScale = " + this.mScale);
   Log.d(TAG, "ScalingRunnalable this.mIsFinished = " + this.mIsFinished);
   PullToZoomListView.this.post(this);
  }
 }

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

(0)

相关推荐

  • Android开发实现仿QQ消息SwipeMenuListView滑动删除置顶功能【附源码下载】

    本文实例讲述了Android开发实现仿QQ消息SwipeMenuListView滑动删除置顶功能.分享给大家供大家参考,具体如下: 一.先来效果图 二.实现步骤: 1. 在项目build.gradle里面添加包 compile 'com.baoyz.swipemenulistview:library:1.3.0' 2. xml布局文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  • Android开发listview选中高亮简单实现代码分享

    百度了好几种listview选中高亮的办法都太繁琐太不友好,我在无意中发现了一种简单有效的办法,而且代码量极少 源码如下: MainActivity.java package com.listviewtest; import android.os.Bundle; import android.app.Activity; import android.graphics.drawable.Drawable; import android.view.View; import android.widge

  • android listview进阶实例分享

    上一篇<android listview初步学习实例代码>分享了一个listview初级实例,本文我们看看一个进阶实例. 目录结构: MainActivity2 package com.example1.listviewpracticvce; /* * 本activity实现的功能: * 将数据库中的数据用listview显示出来 */ import com.example1.listviewdao.PersonDAO; import android.app.Activity; import

  • android使用PullToRefresh框架实现ListView下拉刷新上拉加载更多

    本文实例为大家分享了Android实现ListView下拉刷新上拉加载更多的具体代码,供大家参考,具体内容如下 其实谷歌官方目前已经推出ListView下拉刷新框架SwipeRefreshLayout,想了解的朋友可以点击 android使用SwipeRefreshLayout实现ListView下拉刷新上拉加载了解一下: 大家不难发现当你使用SwipeRefreshLayout下拉的时候布局文件不会跟着手势往下滑,而且想要更改这个缺陷好像非常不容易. 虽然SwipeRefreshLayout非

  • android使用SwipeRefreshLayout实现ListView下拉刷新上拉加载

    本文实例为大家分享了android实现ListView下拉刷新上拉加载的具体代码,供大家参考,具体内容如下 这次使用的是系统的SwipeRefreshLayout实现下拉刷新,和设置ListView的滑动监听判断是否滑动到最底部然后加载更多: 这个要比PullToRefreshListView简单很多,想PullToRefreshListView实现下拉刷新上拉加载的可以看这篇博客: android使用PullToRefresh框架实现ListView下拉刷新上拉加载更多 至于使用哪一种大家可以

  • Android ListView与RecycleView的对比使用解析

    ListView,就如其名,是用来显示列表的一种View,而RecycleView,是其的加强版,今天带来的是这两个几乎具有相同的功能的对比使用 先从ListView说起吧 ListView: 1.在布局文件中使用ListView,并为其定义一个id,方便我们之后的调用,宽高与父控件相同 2.准备数据,将数据添加到ArrayAdapter适配器当中 3.在Activity的java文件中使用findviewbyid找到ListView实例,为其设置Adapter 4.实现ListView的ite

  • android listview初步学习实例代码

    在android开发中ListView是比较常用的组件,下面分享一个实例. MainActivity package com.example1.listviewpracticvce; /* * 本例子实现的功能: * 用listview显示给定的一个静态数组,数组定义在string.xml中攻或者activity中 */ import android.net.sip.SipAudioCall.Listener; import android.os.Bundle; import android.a

  • Android ListView实现下拉顶部图片变大效果

    本文实例为大家分享了Android ListView下拉顶部图片变大的具体代码,供大家参考,具体内容如下 在git上查看牛人的代码,发现是反编译别人的代码,还没加注释,代码也没有完全编译完整,所以这里我做的简单的注释,仅供学习. 变量说明 这里变量包含了:自定义返回动画加速度.自定义动画线程.头部图片view,最后的y坐标,做好的比例,做大的比例等. private static final String TAG = "PullToZoomListView"; private stat

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

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

  • JavaScript通过mouseover()实现图片变大效果的示例

    实例如下所示: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="

  • Android UI自定义ListView实现下拉刷新和加载更多效果

    关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆.不过我就没发现比较实用的,要不就是实现起来太复杂,要不就是不健全的.因为小巫近期要开发新浪微博客户端,需要实现ListView的下拉刷新,所以就想把这个UI整合到项目当中去,这里只是一个demo,可以根据项目的需要进行修改. 就不要太在乎界面了哈: 知道你们想要源码了,去下吧:http://download.csdn.net/detail/wwj_748/6373183 自定义ListView: package com.mar

  • Android ListView实现下拉加载功能

    本文实例为大家分享了ListView下拉加载展示的具体代码,供大家参考,具体内容如下 1.MyListView.Java public class MyListView extends ListView implements OnScrollListener { private final static int RELEASE_To_REFRESH = 0;// 下拉过程的状态值 private final static int PULL_To_REFRESH = 1; // 从下拉返回到不刷新

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

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

  • Android ExpandableListView实现下拉刷新和加载更多效果

    支持下拉刷新和加载更多的ExpandableListView,供大家参考,具体内容如下 模拟器有点卡,滑动的时候鼠标不方便 怎么用: XML中声明 <com.xingyi.elonggradletaskdemo.widget.SExpandableListView android:listSelector="@android:color/transparent" android:id="@+id/elv_coupon" android:layout_width

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

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

  • Android使用ListView实现下拉刷新及上拉显示更多的方法

    本文实例讲述了Android使用ListView实现下拉刷新及上拉显示更多的方法.分享给大家供大家参考,具体如下: 今天得需求是做listview+上下拉动在header和footer显示progressdialog,但不影响用户操作 直接上代码,我已经加上注释了,自己看. package com.stay.main; import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.HashMap;

  • android 有阻尼下拉刷新列表的实现方法

    本文将会介绍有阻尼下拉刷新列表的实现,先来看看效果预览: 这是下拉状态: 这是下拉松开手指后listView回滚到刷新状态时的样子: 1. 如何调用 虽然效果图看起来样子不太好看,主要是因为那个蓝色的背景对不对,没关系,这只是一个背景而已,在了解了我们这个下拉刷新列表的实现之后,你就可以很轻松地修改这个背景,从而实现你想要的UI效果!话不多说,下面我们先来讲讲这个下拉刷新列表是如何使用的,这也是我们编写代码所要实现的目标. final PullToRefreshListView eListVie

随机推荐