`
iaiai
  • 浏览: 2204104 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

慕课网app下拉刷新图标填充效果的实现

 
阅读更多
之前看到一种下拉刷新的效果,与以往的下拉效果都不一样,大多数下拉刷新都是一个圆形进度条在旋转,而这个下拉刷新则是一个不断填充的效果。本以为这是个自定义View,后来反编译慕课网的app后提取资源的时候看到好多的图片,那大概慕课网app内部的实现应该是帧动画达到这种效果。而当我看到这种效果的时候,由于前段时间在学自定义控件,所以本能的反应则是自定义的。首先我们看下慕课网的效果。如下图

而我的也实现了一个这个图标填充的简单版。如下图

整个实现使用图形的混合模式+贝塞尔曲线,贝塞尔曲线的绘制参考自爱哥的博客  贝塞尔曲线内容

资源文件就只有下面这个图标,该图标提取自慕课网app,然后对内部的火焰进行透明处理过

既然是自定义View,那就要继承View,实现onDraw,onMeasure等方法,这里将控件的宽度高度直接设置为图片的宽度和高度加上内边距,并且去实现相应的逻辑去判断MeasureSpec的模式是哪个从而进行处理。

先贴代码
package cn.edu.zafu.view;  
  
import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.Bitmap.Config;  
import android.graphics.BitmapFactory;  
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.Paint;  
import android.graphics.Path;  
import android.graphics.PorterDuff;  
import android.graphics.PorterDuffXfermode;  
import android.util.AttributeSet;  
import android.view.View;  
  
/** 
 * @author lizhangqu 
 *  
 *         2015-3-5 
 */  
public class CustomView extends View {  
    private PorterDuffXfermode porterDuffXfermode;// Xfermode  
    private Paint paint;// 画笔  
    private Bitmap bitmap;// 源图片  
    private int width, height;// 控件宽高  
    private Path path;// 画贝塞尔曲线需要用到  
    private Canvas mCanvas;// 在该画布上绘制目标图片  
    private Bitmap bg;// 目标图片  
  
    private float controlX, controlY;// 贝塞尔曲线控制点,使用三阶贝塞尔曲线曲线,需要两个控制点,两个控制点都在该变量基础上生成  
    private float waveY;// 上升的高度  
  
    private boolean isIncrease;// 用于控制控制点水平移动  
  
    private boolean isReflesh = true;// 是否刷新并产生填充效果,默认为true  
  
    /** 
     * @return 是否刷新 
     */  
    public boolean isReflesh() {  
        return isReflesh;  
    }  
  
    /** 
     * 提供接口设置刷新 
     *  
     * @param isReflesh 
     */  
    public void setReflesh(boolean isReflesh) {  
        this.isReflesh = isReflesh;  
        //重绘  
        postInvalidate();  
    }  
  
    /** 
     * @param context 
     */  
    public CustomView(Context context) {  
        this(context, null);  
    }  
  
    /** 
     * @param context 
     * @param attrs 
     */  
    public CustomView(Context context, AttributeSet attrs) {  
        this(context, attrs, 0);  
    }  
  
    /** 
     * @param context 
     * @param attrs 
     * @param defStyle 
     */  
    public CustomView(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
        init();  
    }  
  
    /** 
     * 初始化变量 
     */  
    private void init() {  
        // 初始化画笔  
        paint = new Paint();  
        paint.setAntiAlias(true);  
        paint.setDither(true);  
        paint.setStyle(Paint.Style.FILL);  
        paint.setColor(Color.parseColor("#ffc9394a"));  
        // 获得资源文件  
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mooc);  
        // 设置宽高为图片的宽高  
        width = bitmap.getWidth();  
        height = bitmap.getHeight();  
  
        // 初始状态值  
        waveY = 7 / 8F * height;  
        controlY = 17 / 16F * height;  
  
        // 初始化Xfermode  
        porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);  
        // 初始化path  
        path = new Path();  
        // 初始化画布  
        mCanvas = new Canvas();  
        // 创建bitmap  
        bg = Bitmap.createBitmap(width, height, Config.ARGB_8888);  
        // 将新建的bitmap注入画布  
        mCanvas.setBitmap(bg);  
  
    }  
  
    @Override  
    protected void onDraw(Canvas canvas) {  
        // 画目标图,存在bg上  
        drawTargetBitmap();  
        // 将目标图绘制在当前画布上,起点为左边距,上边距的交点  
        canvas.drawBitmap(bg, getPaddingLeft(), getPaddingTop(), null);  
        if (isReflesh) {  
            // 重绘,使用boolean变量isReflesh进行控制,并对外提供访问的接口,默认为true且刷新  
            invalidate();  
        }  
    }  
  
    private void drawTargetBitmap() {  
        // 重置path  
        path.reset();  
        // 擦除像素  
        bg.eraseColor(Color.parseColor("#00ffffff"));  
  
        // 当控制点的x坐标大于或等于终点x坐标时更改标识值  
        if (controlX >= width + 1 / 2 * width) {  
            isIncrease = false;  
        }  
        // 当控制点的x坐标小于或等于起点x坐标时更改标识值  
        else if (controlX <= -1 / 2 * width) {  
            isIncrease = true;  
        }  
  
        // 根据标识值判断当前的控制点x坐标是该加还是减  
        controlX = isIncrease ? controlX + 10 : controlX - 10;  
        if (controlY >= 0) {  
            // 波浪上移  
            controlY -= 1;  
            waveY -= 1;  
        } else {  
            // 超出则重置位置  
            waveY = 7 / 8F * height;  
            controlY = 17 / 16F * height;  
        }  
  
        // 贝塞尔曲线的生成  
        path.moveTo(0, waveY);  
        // 两个控制点通过controlX,controlY生成  
        path.cubicTo(controlX / 2, waveY - (controlY - waveY),  
                (controlX + width) / 2, controlY, width, waveY);  
        // 与下下边界闭合  
        path.lineTo(width, height);  
        path.lineTo(0, height);  
        // 进行闭合  
        path.close();  
  
        // 以上画贝塞尔曲线代码参考自爱哥博客  
        // http://blog.csdn.net/aigestudio/article/details/41960507  
  
        mCanvas.drawBitmap(bitmap, 0, 0, paint);// 画慕课网logo  
        paint.setXfermode(porterDuffXfermode);// 设置Xfermode  
        mCanvas.drawPath(path, paint);// 画三阶贝塞尔曲线  
        paint.setXfermode(null);// 重置Xfermode  
    }  
  
    @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
        // 获得宽高测量模式和大小  
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
        // 保存测量结果  
        int width, height;  
  
        if (widthMode == MeasureSpec.EXACTLY) {  
            // 宽度  
            width = widthSize;  
        } else {  
            // 宽度加左右内边距  
            width = this.width + getPaddingLeft() + getPaddingRight();  
            ;  
            if (widthMode == MeasureSpec.AT_MOST) {  
                // 取小的那个  
                width = Math.min(width, widthSize);  
            }  
  
        }  
  
        if (heightMode == MeasureSpec.EXACTLY) {  
            // 高度  
            height = heightSize;  
        } else {  
            // 高度加左右内边距  
            height = this.height + getPaddingTop() + getPaddingBottom();  
            ;  
            if (heightMode == MeasureSpec.AT_MOST) {  
                // 取小的那个  
                height = Math.min(height, heightSize);  
            }  
  
        }  
        // 设置高度宽度为logo宽度和高度,实际开发中应该判断MeasureSpec的模式,进行对应的逻辑处理,这里做了简单的判断测量  
        setMeasuredDimension(width, height);  
  
    }  
  
}

控件的使用
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/ll"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical" >  
    <cn.edu.zafu.view.CustomView   
        android:id="@+id/cv"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:padding="20dp"  
        android:layout_centerInParent="true"  
        android:background="#0000ff"  
        />  
</RelativeLayout>

如果要停止其不断填充的效果,通过函数setReflesh设置isReflesh变量为false即可。
整个实现过程还是相对简单的,基本上注释都讲的很清楚了,这里也不再重复了,文章中涉及到的两个知识点(图形的混合模式和贝塞尔曲线)
  • 大小: 58.1 KB
  • 大小: 2 KB
  • 大小: 3.4 MB
分享到:
评论

相关推荐

    5种uni-app 页面下拉刷新方法-源码示例.zip

    本资料"5种uni-app 页面下拉刷新方法-源码示例.zip"提供了五种不同的实现方式,让我们详细探讨这些方法。 1. **基础API使用:uni.startPullDownRefresh()** uni-app提供了一个名为`uni.startPullDownRefresh()`的...

    下拉刷新功能的源代码,jQuery模拟原生态App 上拉刷新 下拉加载 效果代码.zip

    综上所述,这个压缩包提供的代码资源为开发者提供了一种用jQuery实现原生App下拉刷新和上拉加载效果的方法,通过理解和应用这些代码,可以提升Web应用的交互体验。在实际项目中,可以根据需要进行修改和扩展,以适应...

    H5使用iscroll-4模拟手机app下拉刷新功能实现demo

    最后,为了使下拉刷新功能更加直观,我们还可以添加一些动画效果,如旋转图标或改变文本提示。 需要注意的是,`iscroll-4`虽然强大,但它可能并不适合所有场景。对于复杂的滚动布局,或者需要高性能滚动的项目,...

    微信小程序scroll-view下拉刷新(附带下拉刷新效果)

    在本教程中,我们将探讨如何在`scroll-view`中实现下拉刷新(Pull-to-Refresh)功能,同时提供一个具体的效果展示。 首先,`scroll-view`是微信小程序提供的一个可滚动视图容器,它支持水平滚动和垂直滚动。通过...

    QT-QML下拉刷新上拉加载更多(仿京东app)

    本文将深入探讨如何使用QML实现类似京东APP的下拉刷新和上拉加载更多的功能。 首先,我们要了解`ListView`是QML中的核心组件之一,它允许我们创建可滚动列表,展示大量数据。在实现下拉刷新和上拉加载功能时,`...

    基于Vue和JavaScript的慕课网APP界面设计源码

    本项目是基于Vue和JavaScript开发的慕课网APP界面仿制,包含48个文件,其中包括15个JavaScript脚本、12个PNG图像、7个Vue组件、5个JPG图像、2个Markdown文档、2个JSON配置文件、1个Babel配置文件、1个EditorConfig...

    慕课网App启动引导页

    高仿慕课网App启动引导页,欢迎大家下载学习,有问题可以联系我互相交流。

    Android 仿抖音APP下拉刷新功能.rar

    Android 仿抖音APP下拉刷新功能,首先分析这个效果的实现思路,大致如下:  1、上拉时页面有翻页效果,可以用scrollview的pagingEnabled来实现,也就是说列表页不管你用tableview还是collectionview,只要每个cell...

    Android自带下拉刷新的代码例子

    你需要实现`OnRefreshListener`接口,重写`onRefresh()`方法,这将在用户触发下拉刷新时被调用: ```java SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout); swipeRefreshLayout....

    手机屏幕自动定时下拉刷新

    自动、定时下拉刷新手机屏幕,用于某些软件自动下拉刷新数据

    水滴效果的下拉刷新

    在Android应用开发中,"水滴效果的下拉刷新"是一种常见的用户界面特效,它能够增强用户的交互体验,使得刷新列表的操作更具视觉吸引力。这种效果通常应用于ListView、RecyclerView等滚动视图,当用户上拉列表时,会...

    android仿美团下拉刷新效果

    在这个案例中,我们讨论的主题是"android仿美团下拉刷新效果",这表示我们将实现一个与美团App类似的下拉刷新动画和交互。 首先,下拉刷新效果通常由两个主要组件构成:刷新指示器和刷新逻辑。刷新指示器是用户可以...

    scroller头上拉变化,下拉刷新效果

    总的来说,实现“scroller头上拉变化,下拉刷新效果”涉及到了Android的触摸事件处理、自定义视图、动画以及可能的网络请求和数据刷新逻辑。通过深入理解这些概念和技术,开发者可以创建更加动态和用户友好的应用...

    下雨效果的下拉刷新.zip

    1. **源代码**:包含Objective-C或Swift的源码,实现下拉刷新功能的核心逻辑和动画效果。 2. **资源文件**:可能包括雨滴的图片或SpriteKit的SKS文件,用于定义雨滴精灵的外观和行为。 3. **示例项目**:一个运行中...

    uni-app:mescroll-nui下拉刷新组件

    本知识点主要聚焦于uni-app中的mescroll-nui下拉刷新组件,这是一个非常实用的功能,用于实现用户在滚动到页面顶部时触发数据的刷新。 首先,mescroll-nui是基于MeScroll库的一个uni-app插件,MeScroll是一个高性能...

    下拉刷新效果

    下拉刷新效果是一种常见的UI交互设计,广泛应用于各种移动设备上的应用,如手机App和桌面软件,特别是新闻阅读、社交网络、电商应用等。这种效果为用户提供了方便的方式来获取最新的内容,只需简单地从顶部向下滑动...

    高仿京东2020版首页下拉刷新效果

    本项目"高仿京东2020版首页下拉刷新效果"专注于模仿京东APP的刷新设计,以提供相似的视觉效果和操作感受。通过GitHub项目地址(https://github.com/baiyuliang/JdRefresh)可以获取到完整的源代码,供开发者研究和...

    Android手把手实战APP首页 下拉刷新 自动加载源码

    SwipeRefreshLayout是谷歌提供的一个用于实现下拉刷新效果的组件,它可以包裹一个可滚动视图,例如ListView或RecyclerView。当用户在顶部下拉时,它会显示一个旋转指示器,表示正在刷新数据。 以下是一个简单的 ...

    HTML5模拟原生APP上拉加载,下拉刷新

    在移动设备上,用户习惯于原生APP的流畅体验,包括上拉加载更多内容和下拉刷新页面的功能。本教程将深入探讨如何使用HTML5和jQuery来模拟这些原生APP特性。 一、HTML5基础 HTML5新增了许多元素和API,如`&lt;article&gt;`...

    上下拉控件

    下拉刷新、上拉加载更多、可添加自定义(固定、可滑动)头部控件(例如慕课网app顶部的广告位)

Global site tag (gtag.js) - Google Analytics