android swiperefreshlayout 自定义,自定义一个更好用的SwipeRefreshLayout(弹力拉伸效果详解)...

前言

熟悉SwipeRefreshLayout的同学一定知道,SwipeRefreshLayout是android里面专为RecyclerView,NestedScrollView提供下拉刷新动画的一个控件。可是在使用过程中有些局限性,例如只支持上述控件,不支持ListView,GridView等,另外下拉的动画效果很难更改,而且不支持上拉加载……在很多场景的情况下往往不符合我们的需求。

今天为大家分享的是一个支持上拉下拉加载的控件,代码并非纯原创,改造自github作者baoyz的PullRefreshLayout (有印象最早看到的侧滑删除好像也是他写的),也参考了一些官方SwipeRefreshLayout的源码和网上的一些资料,为了尊重原作者,我还是将其命名为——PullRefreshLayout。

效果如下:

bVEtoG?w=426&h=824

原理

其实是一个ViewGroup,通过对手势的处理,使子控件实现拉动的动画效果,并再加上两个子控件,上拉的loading和下拉的loading(把loading用控件来封装可以很方便的更改动画,真是贴心~),在处理手势拉动的时候,通知他们显示出对应的效果。代码很长,有很多小细节需要注意,在这里我只介绍几个关键的位置,源代码会发在文章的最后。

拖拽弹力效果

大家可以看到,拖拽的时候,是有个弹力效果的,也就是说当拖拽的距离大于某个值,拖动的位移就会慢慢减小,最后会变得拖不动

看上去有点酷炫,其实实现起来就是高中数学知识啦,看下关键代码

final float scrollTop = yDiff * DRAG_RATE;

float originalDragPercent = scrollTop / mTotalDragDistance;

mDragPercent = Math.min(1f, Math.abs(originalDragPercent));//拖动的百分比

float extraOS = Math.abs(scrollTop) - mTotalDragDistance;//弹簧效果的位移

float slingshotDist = mSpinnerFinalOffset;

//当弹簧效果位移小余0时,tensionSlingshotPercent为0,否则取弹簧位移于总高度的比值,最大为2

float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2) / slingshotDist);

//对称轴为tensionSlingshotPercent = 2的二次函数,0到2递增

float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;

float extraMove = (slingshotDist) * tensionPercent * 2;

targetY = (int) ((slingshotDist * mDragPercent) + extraMove);

解释下几个参数

yDiff —— 根据手势算出的滑动位移

scrollTop —— yDiff乘上一个固定的比率(现在是0.5),可以用来调节“弹簧”的弹性系数

mTotalDragDistance —— 当进度显示100%时的位移

originalDragPercent —— 根据scrollTop与mTotalDragDistance的比值

mDragPercent —— 由于originalDragPercent可能大于1,所以mDragPercent才是拖动的百分比

slingshotDist —— 超过100%后可以被允许拖动的最大距离的二分之一,也是一个常数(现在值 = mSpinnerFinalOffset = mTotalDragDistance)

extraMove —— 弹力距离

targetY —— 想要移动到的目标位置

啊!? 被发现有两个个参数没解释,哈哈,至于tensionSlingshotPercent和tensionPercent,就是弹力效果的关键啦

extraOS 在scrollTop>=0时,是从-mTotalDragDistance开始线性递增的,在scrollTop = mTotalDragDistance时,extraOS = 0

tensionSlingshotPercent 在scrollTop从0到mTotalDragDistance阶段,始终为0,在smTotalDragDistance到3*mTotalDragDistance阶段,线性递增,之后一直为2

extraMove 的变化同tensionSlingshotPercent

tensionPercent 是个二次函数,同样映射到scrollTop的变化,在scrollTop从0到mTotalDragDistance阶段,始终为0,在mTotalDragDistance到3mTotalDragDistance阶段,二次函数递增,在3mTotalDragDistance之后恒为0.5

而targetY,在scrollTop从0到mTotalDragDistance阶段,也就是mDragPercent从0到1,extramMove始终为0,然后二次函数递增,在scrollTop > 3*mTotalDragDistance 变为恒值

总结下来targetY相对于scrollTop对函数图像如下:

bVEux8?w=892&h=622

其实看到这个图,我想大家就基本上知道具体出来的效果了,再后面就是一些位移的操作,大家可以看文章最后面源码,值得注意的是,之前都是分析scrollTop > 0 的情况,也就是下拉操作,上拉targetY要取负的,而且上拉下拉都是走这套逻辑,所以计算extraOS的时候scrollTop加上了绝对值

loading动画

在前文中我们说过,loading效果其实是交给两个子控件完成的,这样有利于更改loading的动画效果。那么,具体是怎么实现的呢?

在代码中我们可以看到如下几个对象,其中mRefreshView和mLoadView就是我们所说的loading控件,但它们只是一个容器,只控制显隐,而具体的动画实现是交给对应的mRefreshDrawable和mLoadDrawable;

bVEwGO?w=846&h=522

那我们选取其中一个进行分析,在初始化函数中,可以看到如下代码

bVEwIW?w=983&h=604

setRefreshDrawable方法走进去,发现其实就是把一个Drawable对象赋给mRefreshView,那我们来看一下传入的参数PlaneDrawable,这个是我写的那个火箭飞行的动画效果,代码很简单,但是我们发现PlaneDrawable是继承了一个叫RefreshDrawable的类,对,它才是将动画效果解耦于PullRefreshLayout的关键、

我们看下它的代码

import android.content.Context;

import android.graphics.ColorFilter;

import android.graphics.PixelFormat;

import android.graphics.drawable.Animatable;

import android.graphics.drawable.Drawable;

/**

* Created by baoyz on 14/10/29.

*/

public abstract class RefreshDrawable extends Drawable implements Drawable.Callback, Animatable {

private PullRefreshLayout mRefreshLayout;

public RefreshDrawable(Context context, PullRefreshLayout layout) {

mRefreshLayout = layout;

}

public Context getContext(){

return mRefreshLayout != null ? mRefreshLayout.getContext() : null;

}

public PullRefreshLayout getRefreshLayout(){

return mRefreshLayout;

}

public abstract void setPercent(float percent);

public abstract void setColorSchemeColors(int[] colorSchemeColors);

public abstract void offsetTopAndBottom(int offset);

@Override

public void invalidateDrawable(Drawable who) {

final Callback callback = getCallback();

if (callback != null) {

callback.invalidateDrawable(this);

}

}

@Override

public void scheduleDrawable(Drawable who, Runnable what, long when) {

final Callback callback = getCallback();

if (callback != null) {

callback.scheduleDrawable(this, what, when);

}

}

@Override

public void unscheduleDrawable(Drawable who, Runnable what) {

final Callback callback = getCallback();

if (callback != null) {

callback.unscheduleDrawable(this, what);

}

}

@Override

public int getOpacity() {

return PixelFormat.TRANSLUCENT;

}

@Override

public void setAlpha(int alpha) {

}

@Override

public void setColorFilter(ColorFilter cf) {

}

}

它是一个抽象类,抽象方法有

public abstract void setPercent(float percent);

public abstract void setColorSchemeColors(int[] colorSchemeColors);

public abstract void offsetTopAndBottom(int offset);

为了代码简洁,主题颜色我没有用,还剩下setPercent和offsetTopAndBottom,这两个方法会分别在PullRefreshLayout里面拉动的进度改变和被拉动目标控件位移变化时被调用。这样,我们想更改动画效果就简单了,直接写一个类,继承至RefreshDrawable,然后在对应的setPercent和offsetTopAndBottom里面做出相应的动画数据改变,就如PlaneDrawable那样,然后再调用PullRefreshLayout的setRefreshDrawable或setLoadDrawable方法进行设值,是不是很方便?

同时显示两个动画处理

在添加上拉加载效果时,我发现,假如你先下拉然后在不松手的情况下再上拉,那就会同时出现两个loading动画,然而此时list还不在底部,也就是不应该显示上拉loading效果的。这是由于在拉动时,判断子控件是否可以向上滑动的那个方法会返回false,那么如何解决这个问题呢?

用一个变量mLastDirection储存本次动画的,如果下次的动画与本次不同,则不进行下次动画,并在ACTION_UP和ACTION_CANCEL时,判断被拉动目标控件的top位置

bVEw4y?w=1126&h=450

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以通过编写代码来实现一个简单的跳跃动作,具体实现方式可以根据不同的编程语言和游戏引擎来进行选择和实现。一般来说,需要定义跳跃的高度、跳跃的速度和跳跃的时间等参数,并在游戏中触发跳跃动作的条件下执行相应的代码逻辑。 ### 回答2: 要实现一个简单的跳跃动作,可以按照以下步骤进行: 1. 设计角色模型:首先需要设计一个角色模型,包括模型的外观和动画。角色应该有一个站立的初始状态和一个跳跃的动作。 2. 定义跳跃按键:选择一个按键作为触发跳跃动作的按键,如空格键或者上箭头键。 3. 检测按键输入:使用编程语言或者游戏引擎提供的输入检测功能,监测到跳跃按键被按下时触发跳跃动作。 4. 角色跳跃:按下跳跃按键后,角色应该从站立状态开始,施加一个向上的力或者应用一个跳跃动画。可以使用物理引擎或者动画系统来实现这个效果。 5. 添加重力:为了让角色在跳跃后落回地面,需要添加一个重力效果。可以通过每帧更新角色的位置,使其产生下落的效果。 6. 碰撞检测:在游戏中,角色可能需要跳跃过障碍物或者跳到平台上。为了确保跳跃的有效性,需要实现碰撞检测,检测角色是否与障碍物或者平台碰撞,如果碰撞则中断跳跃。 7. 调整跳跃高度和速度:可以根据游戏需求来调整跳跃高度和速度的参数,在实现过程中可以进行迭代和调试。 通过以上步骤,就可以实现一个简单的跳跃动作。当玩家按下跳跃按键时,角色会在一定高度和速度的作用下跳跃起来,并在重力的作用下重新回到地面。 ### 回答3: 要实现一个简单的跳跃动作,可以遵循以下步骤: 1. 设计跳跃动作:首先确定跳跃动作的具体效果,例如跳多高、跳多远,以及跳跃时身体的姿势等。 2. 编写跳跃动作的代码:使用程序语言来编写跳跃动作的代码。首先,需要给角色添加一个跳跃动作的触发条件,例如按下空格键或者触摸屏幕。然后,编写跳跃动作的代码,使角色按照设计好的跳跃效果进行跳跃。 3. 设置跳跃的物理属性:为了实现更真实的跳跃效果,可以给角色添加一些物理属性,例如重力、弹力等。这样,在跳跃时,角色就会受到这些物理属性的影响,使跳跃动作更加自然。 4. 调试和测试:完成代码编写后,需要进行调试和测试,确保跳跃动作的代码能够正常运行,并按照预期效果进行跳跃。 5. 跳跃动作的优化和修改:在测试过程中,可能会发现跳跃动作还存在一些问题或者不足之处。此时,需要根据测试结果对跳跃动作进行优化和修改,以达到更好效果。 总结:实现一个简单的跳跃动作,首先需要设计跳跃的效果,然后编写跳跃动作的代码,并设置物理属性。最后,进行调试和测试,优化跳跃动作,使其更加真实和符合预期。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值