zoukankan      html  css  js  c++  java
  • 循环播放一张图片,如果图片大小小于屏幕,继续使用该图片进行填充

    场景:

      需要做出来的效果差不多如标题所述,即如果屏幕宽度为720,而图片的宽度只有150,现在需要从中间开始,往两边移动该图片,

    我们现在以往右边移动为例,如果往右移动了150,此时绘制了一整个完整图形,继续移动,此时不仅要从中间绘制出新的图形,已经绘制的完整图形也得向右移动。进而达到动画的效果。

    分析:

      为了达到上面的效果,最开始想到的是使用动画,但是发现:

      1)如果选择平移动画,只能移动图片,不会保留之前图片走过的路径,这样的话背景图就不会出现连续的情况,而只是有单张图,并不是这里想要的。

      2)选择多张图片循环播放,向gif那样,可如此一来使用到的图片资源过多,也不予考虑。

    解决方案:

      最后决定自己实现一个view,通过在onDraw中不断的从中间向两边绘制一个图片,并平移已绘制的图形,进而达到想要的效果。

      这个看起来有些像游戏中的实现,即一个人物在屏幕中走,其实它一直都是在屏幕中央,只是背景图在不断的往左边绘制。

      

      如图所示。

      目前来看思路还是挺明确的,但是在实现的过程中,还是有一些情况要考虑清楚,这里做个简单的分析。

      1)图片从中间一点点绘制出来,这里需要一个偏移量xOffset,同时移动还有速度,所以得有个变量speed

      2)图片在屏幕中的显示存在两种情况:显示完全,显示不完全。

        i)针对显示不完全的情况,我们需要根据Bitmap的createBitmap来创建新的bitmap并将其绘制出来。

          那么显示不完全的图形的宽度是多少呢?明显的,中间新绘制出来的图形宽度为xOffset,最右边不完整图形的宽度为sourceWidth-超出屏幕的宽度。

          既然要以xOffset为createBitmap的参数来构建新的bitmap,那么xOffset得有个最大值xOffsetLimit,这里得对xOffset的值做个限定【1,xOffsetLimit】,

          每当xOffset+speed>xOffsetLimit时,都得重置xOffset为1.

          此时xOffsetLimit=sourceWidth。

          但是!!

          如果sourceWidth>parentWidth时,xOffset只需限定到parentWidth,即xOffsetLimit=parentWidth。所以xOffsetLimit得取图片和区域宽度中较小的那个。

        ii)显示完全的情况,我们要考虑,整个区域(我们这里以半个屏幕为例),最多能绘制几个完整图形?

          此时很自然的,我们会想到,最多能绘制多少,那就parentWidth(区域宽度)/ sourceWidth(完整图形宽度)= maxCompleteNum(最大完整图形个数)

          但是!!

          同时我们也得考虑到,由于屏幕是在不断移动中的,可能在某一刻,绘制的完整图形个数是maxCompleteNum(如上图,为2),

          但是继续右移时,最右边的完整图形超出了屏幕,而中间新绘制出来的图形却还没有达到完整,此时屏幕中实际存在的完整图形只有1个!!

          所以,这里我们还需要一个变量,记录此时此刻在屏幕中所能绘制的完整图形个数completeNumBeforeOut。

       3)通过以上分析,我们知道屏幕中最多出现maxCompleteNum个完整图形,某个时刻绘制的完整图形个数应为completeNumBeforeOut。但是屏幕一直在绘制,我们怎么知道completeNumBeforeOut的值?

          此时,我们得先有个变量drawnNum,即从开始到某个时刻,已经绘制的完整图形的个数。每当xOffset加完speed,都会去判断是否超过了xOffsetLimit,如果超过了,在将xOffset置回1的同时,也会让drawnNum加1.

          但由于最多只能绘制maxCompleteNum个完整图形,所以当drawnNum加完1之后,还得将其限制在【0,maxCompleteNum】。

          由于drawnNum是从开始到现在所绘制的完整图形个数,所以它是一直递加直到最大值,那么当前这个时候,到底有几个完整图形显示在屏幕中?

          此时得用循环来判断了。如果xOffset+ i*sourceWidth <= screenWidth(屏幕宽度),表示还没有超过屏幕,即i对应的这个图形还是完整的,所以此时completeNumBeforeOut可加1.其中i的范围是【1,drawnNum】

       4)此外,我们还得记录当前这个时刻,绘制的图形是否已经超出了屏幕,即该有个变量hasExist。

          hasExist = xOffset+drawnNum*sourceWidth > screenWidth。这个应该不难理解了,需要注意的是,这里表达式及上一个表达式,都是假定xOffset是相对屏幕中间而言的,事实上计算式得加上screenWidth/2。

       5)目前位置,变量差不多都齐全了,我们开始进行绘制。

          先判断当前屏幕中是否有完整图形存在,即completeNumBeforeOut,如果大于0,则在相应位置绘制出相应的个数。

          接着将从中间新移动出的图形绘制出来,其宽度为xOffset。

          最后,得用到上面的hasExist进行判断。即如果hasExist为false,那么还没有超出屏幕,则不进行操作。

            如果hasExist为true,即已经超过了屏幕了,那么绘制最右边的图形。

      6)以上流程下来,看起来挺不错的,事实上还存在一个挺大的问题。

        由于xOffset每次都是加speed,所以当xOffset达到最大值的时候,往往不会等于xOffsetLimit,而是

          maxOffsetCount(xOffset超过limit前可添加speed的最大次数) = (xOffsetLimit - 1) / 2;

          maxOffset(xOffset的最大值) = 1+ maxOffsetCount * speed;

          在以上判断是否超出屏幕的判断总,我们是假定xOffset + drawnNum * sourceWidth > screenWidth一定会满足条件。

          但事实上,由于drawnNum存在最大值maxCompleteNum,而xOffset也存在最大值maxOffset,存在这样一种情况,即maxOffset + maxCompleteNum * sourceWidth任然还差一些,不能超过screenWidth。

          (以sourceWidth=147,parentWidth=720为例,此时最多可绘制1个完整图形,最大偏移量为136,而要超出屏幕xoffset必须要达到139.5 。因为136在加上一个speed(15)就又还原了,所以此时不可能会超出屏幕)

          为了避免以上情况,当判断maxOffset + maxCompleteNum * sourceWidth < screenWidth时,得使maxCompleteNum加上1!!

    之后附上源码

  • 相关阅读:
    sqlite错误 Abort due to constraint violation column id is not unique id没开启自动增长
    字符串转为日期类型
    XPTable 一行添加数据 如果想添加多行 可以使用for循环
    在逮捕异常的时候 可以获取e.MESSAGE里面的信息 然后判断是什么异常
    C# 加载图片image (C#)Image.FromFile 方法会锁住文件的原因及可能的解决方法
    计算两个时间的前后 时间戳
    用C#语言写的多线程演示程序:两个线程,可以开始,可以暂停,可以恢复,可以清除。
    sqlite插入日期时候 出现18991230 0:00:00
    datagridview绑定dataset的时候 需要这一句
    WinForm 子线程修改主线程(UI线程)Control 【Z】
  • 原文地址:https://www.cnblogs.com/ivan-aldrich/p/5012798.html
Copyright © 2011-2022 走看看