无限滚动的ImageView

无限滚动的ImageView



1)链接

github上地址为:  https://github.com/Q42/AndroidScrollingImageView

附效果图:

2)实现源码

源码比较少,在此贴上自定义属性和代码:


<?xml version="1.0" encoding="utf-8"?>

<resources>

    <declare-styleable name="ScrollingView">

        <attr name="src" format="reference"/>

        <attr name="speed" format="dimension"/>

    </declare-styleable>

</resources>

代码:

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

import static java.lang.Math.abs;

public class ScrollingView extends View {

    private static final String TAG = ScrollingView.class.getSimpleName();
    private int speed;
    private Bitmap bitmap;
    private boolean isStarted = false;
    private float offset;
    private Rect clipBounds = new Rect();

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

    public ScrollingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScrollingView, 0,0);

        try{
            speed = typedArray.getDimensionPixelSize(R.styleable.ScrollingView_speed, 1);
            bitmap = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(R.styleable.ScrollingView_src, 0));
        }finally {
            typedArray.recycle();
        }
        start();
    }

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

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    protected void onDraw(Canvas canvas) {
        if (canvas == null) {
            return;
        }
        //拿到画布的大小
        canvas.getClipBounds(clipBounds);
        //获取src的图片宽度
        float layerWidth = bitmap.getWidth();
        //后面如果开启了滚动动画,那么将会不断减少位移,这里判断如果减少的位移已经不少于src图片宽度时,则让其复位,不然在下面的循环中将会重复绘制多遍影响性能
        //源码中的写的较复杂,不理解,这里我直接改成了复位为0
        if (offset < -layerWidth) {
//            offset += (floor(abs(offset) / layerWidth) * layerWidth);
            offset = 0;
        }
        //使用一个变量接收一下位移量
        float left = offset;
        //如果left不大于画布的宽度,则循环绘制
        while (left < clipBounds.width()) {
            //前提说明:
            //通过drawBitmap进行绘制,这里的核心是通过控制左边的起始绘制坐标来达成图片的滚动效果
            //left为负数时,起始点将在绘制原点偏左,但是控件显示区域不变,这样将会使得图片的左边一块区域不会显示,右边空一块(附图)
            //left为正数时,起始点将在绘制原点偏右,但是控件显示区域不变,这样将会使得图片的右边一块区域不会显示,左边空一块
            //所以通过控制left参数,就可以达成拼接图片的目的!就相当于把图片从中间某一个地方剪开,把左边的图片

            //原理:将left坐标通过speed速度进行变化不断偏移,然后基于left进行绘制,此处while循环和left+=layoutWidth是为了画布中不出现空白断节的目的,如果改成if的话,当left偏移足够多时,就没法接头造成显示空白断截的情况
            //其中,关于方向的控制,设置为speed为正时,滚动方向为从右到左;
            // 为负数时,滚动方向从左到右
            //具体控制手段为:为正时,getBitmapLeft方法不作处理,left将会与偏移量offset一致越负越多,导致左边的绘制坐标从开始不断向左,图片会从左向右绘制直到把右边画布填满,达到图片在从右向左滚的效果
            //为正数时,getBitmapLeft方法对left进行处理,为了使方向相反,需要使绘制坐标从开始不断向右,所以返回的是clipBounds.width() +(- layerWidth) - left;
            //图片会从右向左绘制直到把左边填充满,之所以需要-layoutWidth,是因为如果画布宽度是图片宽度的几倍时,没有减去的话最左边的一个图片宽度将会出现空白出现断层(left将不能从最左边开始画)
            canvas.drawBitmap(bitmap, getBitmapLeft(layerWidth, left), 0, null);
            left += layerWidth;
            //PS:left是接收的offset值,该值在下面的代码中是一直递减的(offset -= abs(speed);)
        }
        if (isStarted) {
            offset -= abs(speed);
            //通过speed修改偏移量重绘
            postInvalidateOnAnimation();
        }
    }

    /**
     * 用于设置drawBitmap时左边的坐标,控制滚动的方向,
     * 当速度为正数时,将left坐标原样返回,滚动方向为从右到左(返回的left的变化趋势将会从0一直减少到-layoutWidth)
     * 当速度为负数时,则取全left剩余的部分,滚动方向从左到右(返回的数的变化趋势将会从clipBounds.width() - layerWidth增加到clipBounds.width())
     * @param layerWidth bitmap图片的宽度
     * @param left       当前的left坐标,即记录的offset位移量
     * @return
     */
    private float getBitmapLeft(float layerWidth, float left) {
        if (speed < 0) {
            return clipBounds.width() - layerWidth - left;
        } else {
            return left;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), bitmap.getHeight());
    }

    /**
     * Start the animation
     */
    public void start() {
        if (!isStarted) {
            isStarted = true;
            postInvalidateOnAnimation();
        }
    }

    /**
     * Stop the animation
     */
    public void stop() {
        if (isStarted) {
            isStarted = false;
            invalidate();
        }
    }

    public boolean isStarted(){
        return isStarted;
    }

}

总结:其核心逻辑可见注释,即通过不断改变drawBitmap方法的左边起始绘制坐标来控制图片的左右横向滚动。同理,有兴趣的小伙伴可以参考这个思路实现一下ImageView的竖直方向上的无限滚动。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-05 19:32:20

无限滚动的ImageView的相关文章

iOScollectionView广告无限滚动(Swift实现)

今天公司里的实习生跑过来问我一般App上广告的无限滚动是怎么实现的,刚好很久没写博客了,就决定写下了,尽量帮助那些处于刚学iOS的程序猿. 做一个小demo,大概实现效果如下图所示: 基本实现思路: 1. 在你需要放置无限滚动展示数据的地方把他的数据,在原本的基础上把你要展示的数据扩大三倍.(当然扩大两倍也是可以的,三倍的话,比较好演示) // MARK: - 设置数据源 func collectionView(_ collectionView: UICollectionView, number

iOS开发:一个无限滚动自动播放图片的Demo(Swift语言编码)

很久以前就想写这么一个无限滚动的Demo了,最近学习了下Swift,手中没有可以用来练手的Demo,所以才将它实现了. Github地址(由于使用了UIView+AutoLayout第三方进行布局,所以Github判断主要语言是OC):https://github.com/wzpziyi1/DisplayingImage 使用UICollectionView来实现的,不同于UIScrollView实现的一点是,就是不需要再手动实现缓存池功能,因为UICollectionView中的cell本就是

iOS_UIScrollView实现无限滚动,思路与代码

UIScrollView实现无限滚动的三种思路. 当然只是我的一些用法,当然还有非常多的实现方式,如果大家有好的实现思路也可以告诉我,相互学习嘛~ UIScrollView无限滚动 第一种方式: 原理:利用结束的位置来重新设置ScrollView ContentOffset的值,让人产生视觉上的无限循环,优点:代码易懂,缺点,会创建多余的内存. 第二种方式: 原理:利用中间的两个变量来当前的View及缓冲的View,只创建两个View,将当前的View放在中间.判断滑动的位置,优先去缓冲的Vie

LoopBar: Tap酒吧与无限滚动

相约工具栏 - 标签栏与无限滚动为Android由Cleveroad 在Cleveroad我们最近认识到通过使用任何一个应用程序类别的导航,导航面板是很无聊和琐碎.这就是为什么我们的设计师的创意武装,我们向您介绍了基于Android的应用,我们的新组件 - LoopBar.当时的想法是让导航菜单就在指纹,在标签栏.更重要的是认为有一些特定的功能,使其从类似的人群中脱颖而出.因此,尝试在你的应用程序的LoopBar库,你会看到其中的差别. 如果你努力创造不寻常的外观和导航的应用程序,欢迎你使用循环

利用递归 实现UIScrollView无限滚动的效果

项目需求 利用递归 实现UIScrollView无限滚动的效果. 上机试题, #import "ViewController.h" @interface ViewController (){ UIScrollView *mainScroll; BOOL isFinish; int x; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; x=0; isFinish = YES;

用原生的javascript 实现一个无限滚动的轮播图

说一下思路:和我上一篇博客中用JQ去写的轮播图有相同点和不同点 相同点: 首先页面布局是一样的 同样是改变.inner盒子的位置去显示不同的图片 不同点: 为了实现无限滚动需要多添加两张重复的图片 左右切换和前面的方法有所不同,前面是获取当前的索引值乘以-600px当做位移距离,现在是需要获取当前.inner的位置来加上或者减去-600来实现 下面来一步步的去实现轮播图: 首先是html <!DOCTYPE html> <html lang="en"> <

Android 高级UI设计笔记09:Android如何实现无限滚动列表

ListView和GridView已经成为原生的Android应用实现中两个最流行的设计模式.目前,这些模式被大量的开发者使用,主要是因为他们是简单而直接的实现,同时他们提供了一个良好,整洁的用户体验. 对于ListView和GridView一个共同基本要求是:当用户向下滚动时可以动态加载数据支持无限滚动.下面教你如何在自己的应用中实现这个特性. 具体流程如下: (1)我们需要的一个主要组件是InfiniteScrollListener类,它实现了OnScrollListener接口.让我们直接

基于HTML5+CSS3的图片旋转、无限滚动、文字跳动特效

本文分享几种基于HTML5+CSS3实现的一些动画特效:图片旋转.无限滚动.文字跳动;实现起来均比较容易,动手来试试! 一.图片旋转 效果图如下: 这个效果实现起来其实并不困难.代码清单如下: <style type="text/css"> #liu{ width:280px; height: 279px; background: url(shishi.png) no-repeat; border-radius:140px; -webkit-animation:run 6s

Cocos2d-x 《雷电大战》-双层地图无限滚动

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文要实现飞机射击游戏中的地图无限滚动的功能,这里分为两个层,一个层无限向下滚动,一个层无限向上滚动,这样子结合起来效果就非常有层次感,也非常逼真,这里我把地图层都写成一个类,自己把地图改下,就可以成为你自己的了!下面,我们开始吧 先来看看效果: Cocos2d-x版本:3.4 工程环境:VS30213 一.实现思路 其实就是两张图片,然后同时一起向下(向上)滚动,当一张图片完全出视野后,就