【问题标题】:Android ImageView blur animationAndroid ImageView 模糊动画
【发布时间】:2014-09-09 15:41:39
【问题描述】:

我希望为 ImageView 添加模糊动画,但要设置持续时间。因此,例如,我希望图像随着时间的推移而变得模糊。

我已经有了模糊图像的方法,但我需要让它在 2 秒内从模糊变为无模糊。

谁能帮帮我?

编辑:这是我目前必须模糊图像的方法。

public Bitmap blur(Bitmap sentBitmap, int radius) {

    // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>

    Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);

    if (radius < 1) {
        return (null);
    }

    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    int[] pix = new int[w * h];
    Log.e("pix", w + " " + h + " " + pix.length);
    bitmap.getPixels(pix, 0, w, 0, 0, w, h);

    int wm = w - 1;
    int hm = h - 1;
    int wh = w * h;
    int div = radius + radius + 1;

    int r[] = new int[wh];
    int g[] = new int[wh];
    int b[] = new int[wh];
    int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
    int vmin[] = new int[Math.max(w, h)];

    int divsum = (div + 1) >> 1;
    divsum *= divsum;
    int dv[] = new int[256 * divsum];
    for (i = 0; i < 256 * divsum; i++) {
        dv[i] = (i / divsum);
    }

    yw = yi = 0;

    int[][] stack = new int[div][3];
    int stackpointer;
    int stackstart;
    int[] sir;
    int rbs;
    int r1 = radius + 1;
    int routsum, goutsum, boutsum;
    int rinsum, ginsum, binsum;

    for (y = 0; y < h; y++) {
        rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
        for (i = -radius; i <= radius; i++) {
            p = pix[yi + Math.min(wm, Math.max(i, 0))];
            sir = stack[i + radius];
            sir[0] = (p & 0xff0000) >> 16;
            sir[1] = (p & 0x00ff00) >> 8;
            sir[2] = (p & 0x0000ff);
            rbs = r1 - Math.abs(i);
            rsum += sir[0] * rbs;
            gsum += sir[1] * rbs;
            bsum += sir[2] * rbs;
            if (i > 0) {
                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];
            } else {
                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];
            }
        }
        stackpointer = radius;

        for (x = 0; x < w; x++) {

            r[yi] = dv[rsum];
            g[yi] = dv[gsum];
            b[yi] = dv[bsum];

            rsum -= routsum;
            gsum -= goutsum;
            bsum -= boutsum;

            stackstart = stackpointer - radius + div;
            sir = stack[stackstart % div];

            routsum -= sir[0];
            goutsum -= sir[1];
            boutsum -= sir[2];

            if (y == 0) {
                vmin[x] = Math.min(x + radius + 1, wm);
            }
            p = pix[yw + vmin[x]];

            sir[0] = (p & 0xff0000) >> 16;
            sir[1] = (p & 0x00ff00) >> 8;
            sir[2] = (p & 0x0000ff);

            rinsum += sir[0];
            ginsum += sir[1];
            binsum += sir[2];

            rsum += rinsum;
            gsum += ginsum;
            bsum += binsum;

            stackpointer = (stackpointer + 1) % div;
            sir = stack[(stackpointer) % div];

            routsum += sir[0];
            goutsum += sir[1];
            boutsum += sir[2];

            rinsum -= sir[0];
            ginsum -= sir[1];
            binsum -= sir[2];

            yi++;
        }
        yw += w;
    }
    for (x = 0; x < w; x++) {
        rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
        yp = -radius * w;
        for (i = -radius; i <= radius; i++) {
            yi = Math.max(0, yp) + x;

            sir = stack[i + radius];

            sir[0] = r[yi];
            sir[1] = g[yi];
            sir[2] = b[yi];

            rbs = r1 - Math.abs(i);

            rsum += r[yi] * rbs;
            gsum += g[yi] * rbs;
            bsum += b[yi] * rbs;

            if (i > 0) {
                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];
            } else {
                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];
            }

            if (i < hm) {
                yp += w;
            }
        }
        yi = x;
        stackpointer = radius;
        for (y = 0; y < h; y++) {
            // Preserve alpha channel: ( 0xff000000 & pix[yi] )
            pix[yi] = ( 0xff000000 & pix[yi] ) | ( dv[rsum] << 16 ) | ( dv[gsum] << 8 ) | dv[bsum];

            rsum -= routsum;
            gsum -= goutsum;
            bsum -= boutsum;

            stackstart = stackpointer - radius + div;
            sir = stack[stackstart % div];

            routsum -= sir[0];
            goutsum -= sir[1];
            boutsum -= sir[2];

            if (x == 0) {
                vmin[y] = Math.min(y + r1, hm) * w;
            }
            p = x + vmin[y];

            sir[0] = r[p];
            sir[1] = g[p];
            sir[2] = b[p];

            rinsum += sir[0];
            ginsum += sir[1];
            binsum += sir[2];

            rsum += rinsum;
            gsum += ginsum;
            bsum += binsum;

            stackpointer = (stackpointer + 1) % div;
            sir = stack[stackpointer];

            routsum += sir[0];
            goutsum += sir[1];
            boutsum += sir[2];

            rinsum -= sir[0];
            ginsum -= sir[1];
            binsum -= sir[2];

            yi += w;
        }
    }

    Log.e("pix", w + " " + h + " " + pix.length);
    bitmap.setPixels(pix, 0, w, 0, 0, w, h);

    return (bitmap);
}

【问题讨论】:

  • 你为什么不向我们展示你已经拥有的东西?如果我们不得不猜测您已经尝试过什么,您只会让我们更难给您一个好的答案。
  • 只要你能告诉我你用来模糊图像的代码,我就可以回答你的问题。只需在此处与@XaverKapeller 一起写评论,以便在您编辑问题后通知我。
  • 感谢@XaverKapeller 的帮助。我在早上上班时在公交车上更新了答案,因此手头没有任何代码,但现在我已经包含了用于模糊位图的方法供您查看。
  • 我看到你正在使用 Stackblur。这完全没问题,只是为了完整性:使用 Renderscript,您几乎可以获得最好的模糊效果,但除非有需要,否则您不应该切换。 Stackblur 已经足够好了。我需要一些时间来测试一些东西并写下答案。
  • 不幸的是,这种模糊算法非常慢,除非位图非常小,否则您无法可靠地实时模糊位图。如果你想使用这个算法,你应该事先模糊所有你想模糊的图像,然后交叉淡化模糊和非模糊版本。

标签: android animation imageview android-animation


【解决方案1】:

我参加聚会有点晚了,但如果我理解正确的话,你想“淡入模糊”,让它不断增加吗?

您可以通过将两个 ImageView 相互堆叠来实现此效果。下一张显示未触及的图像,上一张是预渲染的模糊图像。上面的必须是不可见的(alpha=0f)。接下来,您淡入上部 ImageView 并淡出下部 ImageView。这会给你想要的效果。您可以通过调整时间和透明度来自定义效果。

祝你好运:)

【讨论】:

    【解决方案2】:
    imageview = (ImageView) itemView.findViewById(R.id.imageView);
    
            BitmapDrawable drawable = (BitmapDrawable) imageview.getDrawable();
            Bitmap bitmap = drawable.getBitmap();
            Bitmap blurred = blurRenderScript(bitmap, 25);
            imageview.setImageBitmap(blurred);   
    

    //这些是模糊方法

    @SuppressLint("NewApi")
        private Bitmap blurRenderScript(Bitmap smallBitmap, int radius) {
    
            try {
                smallBitmap = RGB565toARGB888(smallBitmap);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
            Bitmap bitmap = Bitmap.createBitmap(
                    smallBitmap.getWidth(), smallBitmap.getHeight(),
                    Bitmap.Config.ARGB_8888);
    
            RenderScript renderScript = RenderScript.create(context);
    
            Allocation blurInput = Allocation.createFromBitmap(renderScript, smallBitmap);
            Allocation blurOutput = Allocation.createFromBitmap(renderScript, bitmap);
    
            ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(renderScript,
                    Element.U8_4(renderScript));
            blur.setInput(blurInput);
            blur.setRadius(radius); // radius must be 0 < r <= 25
            blur.forEach(blurOutput);
    
            blurOutput.copyTo(bitmap);
            renderScript.destroy();
    
            return bitmap;
    
        }
    
        private Bitmap RGB565toARGB888(Bitmap img) throws Exception {
            int numPixels = img.getWidth() * img.getHeight();
            int[] pixels = new int[numPixels];
    
            //Get JPEG pixels.  Each int is the color values for one pixel.
            img.getPixels(pixels, 0, img.getWidth(), 0, 0, img.getWidth(), img.getHeight());
    
            //Create a Bitmap of the appropriate format.
            Bitmap result = Bitmap.createBitmap(img.getWidth(), img.getHeight(), Bitmap.Config.ARGB_8888);
    
            //Set RGB pixels.
            result.setPixels(pixels, 0, result.getWidth(), 0, 0, result.getWidth(), result.getHeight());
            return result;
        }
    

    【讨论】:

      【解决方案3】:

      模糊效果在 Android 上总是很困难。本质上,您必须在外观和性能之间做出决定。模糊看起来越好,花费的时间就越长,如果模糊本身不是瞬时的,那么你就无法真正为模糊设置动画。

      你原来的模糊算法产生了非常好的结果,但是因为它也很慢,使得模糊动画变得不可能。为了演示如何有效地模糊此图像,我通过缩小位图创建了一个简单的模糊动画:

      public class BlurAnimation extends Animation {
      
          private final ImageView imageView;
          private final Bitmap bitmap;
          private final float startValue;
          private final float stopValue;
          private final float difValue;
      
          private BlurAnimation(ImageView imageView, Bitmap bitmap, int startValue, int stopValue) {
              this.imageView = imageView;
              this.bitmap = bitmap;
              this.startValue = startValue;
              this.stopValue = stopValue;
              this.difValue = stopValue - startValue;
          }
      
          @Override
          protected void applyTransformation(float interpolatedTime, Transformation t) {
              super.applyTransformation(interpolatedTime, t);
      
              int current = (int)(this.difValue * interpolatedTime + this.startValue + 0.5f);
              Bitmap blurred = quickBlur(this.bitmap, current);
              this.imageView.setImageBitmap(blurred);
          }
      
          public Bitmap quickBlur(Bitmap bitmap, int factor) {
              if(factor <= 0) {
                  return Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
              }
              return Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() / factor, bitmap.getHeight() / factor, true);
          }
      }
      

      这工作得很好(尽管仍有一些滞后),但结果无法与您的模糊算法进行比较,它看起来很糟糕:

      所以你看,在模糊图像时很难将性能和美观结合起来,但首先有一些选项RenderScript。 RenderScript 速度非常快,并且具有内置的高斯模糊滤镜。我从未使用过它,但据我所知,它可能是您问题的解决方案。

      您也可以尝试加载已缩小版本的图像,这将产生与上述 gif 相同的效果,但速度会更快。缺点是在Animation 中使用它会再次出现问题,但如果您只需要模糊图像并且您并不真正关心质量,那么您应该选择此选项。

      您可以找到有关RenderScript 和其他快速模糊选项in this answer 的更多信息

      【讨论】:

        【解决方案4】:

        模糊本身​​需要很长时间,即使在新设备上也是如此。动画模糊会更糟。 RenderScript 也无济于事。最好的办法是在模糊图像和非模糊图像之间交叉淡入淡出:

        package com.example.simon.crossfadeblur;
        
        import android.app.Activity;
        import android.content.Context;
        import android.graphics.Bitmap;
        import android.graphics.BitmapFactory;
        import android.graphics.drawable.BitmapDrawable;
        import android.graphics.drawable.Drawable;
        import android.os.Bundle;
        import android.util.AttributeSet;
        import android.util.Log;
        import android.view.View;
        import android.widget.FrameLayout;
        import android.widget.ImageView;
        
        public class MainActivity extends Activity {
        
            public Bitmap blur(Bitmap sentBitmap, int radius) {
        
                // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
        
                Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
        
                if (radius < 1) {
                    return (null);
                }
        
                int w = bitmap.getWidth();
                int h = bitmap.getHeight();
        
                int[] pix = new int[w * h];
                Log.e("pix", w + " " + h + " " + pix.length);
                bitmap.getPixels(pix, 0, w, 0, 0, w, h);
        
                int wm = w - 1;
                int hm = h - 1;
                int wh = w * h;
                int div = radius + radius + 1;
        
                int r[] = new int[wh];
                int g[] = new int[wh];
                int b[] = new int[wh];
                int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
                int vmin[] = new int[Math.max(w, h)];
        
                int divsum = (div + 1) >> 1;
                divsum *= divsum;
                int dv[] = new int[256 * divsum];
                for (i = 0; i < 256 * divsum; i++) {
                    dv[i] = (i / divsum);
                }
        
                yw = yi = 0;
        
                int[][] stack = new int[div][3];
                int stackpointer;
                int stackstart;
                int[] sir;
                int rbs;
                int r1 = radius + 1;
                int routsum, goutsum, boutsum;
                int rinsum, ginsum, binsum;
        
                for (y = 0; y < h; y++) {
                    rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
                    for (i = -radius; i <= radius; i++) {
                        p = pix[yi + Math.min(wm, Math.max(i, 0))];
                        sir = stack[i + radius];
                        sir[0] = (p & 0xff0000) >> 16;
                        sir[1] = (p & 0x00ff00) >> 8;
                        sir[2] = (p & 0x0000ff);
                        rbs = r1 - Math.abs(i);
                        rsum += sir[0] * rbs;
                        gsum += sir[1] * rbs;
                        bsum += sir[2] * rbs;
                        if (i > 0) {
                            rinsum += sir[0];
                            ginsum += sir[1];
                            binsum += sir[2];
                        } else {
                            routsum += sir[0];
                            goutsum += sir[1];
                            boutsum += sir[2];
                        }
                    }
                    stackpointer = radius;
        
                    for (x = 0; x < w; x++) {
        
                        r[yi] = dv[rsum];
                        g[yi] = dv[gsum];
                        b[yi] = dv[bsum];
        
                        rsum -= routsum;
                        gsum -= goutsum;
                        bsum -= boutsum;
        
                        stackstart = stackpointer - radius + div;
                        sir = stack[stackstart % div];
        
                        routsum -= sir[0];
                        goutsum -= sir[1];
                        boutsum -= sir[2];
        
                        if (y == 0) {
                            vmin[x] = Math.min(x + radius + 1, wm);
                        }
                        p = pix[yw + vmin[x]];
        
                        sir[0] = (p & 0xff0000) >> 16;
                        sir[1] = (p & 0x00ff00) >> 8;
                        sir[2] = (p & 0x0000ff);
        
                        rinsum += sir[0];
                        ginsum += sir[1];
                        binsum += sir[2];
        
                        rsum += rinsum;
                        gsum += ginsum;
                        bsum += binsum;
        
                        stackpointer = (stackpointer + 1) % div;
                        sir = stack[(stackpointer) % div];
        
                        routsum += sir[0];
                        goutsum += sir[1];
                        boutsum += sir[2];
        
                        rinsum -= sir[0];
                        ginsum -= sir[1];
                        binsum -= sir[2];
        
                        yi++;
                    }
                    yw += w;
                }
                for (x = 0; x < w; x++) {
                    rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
                    yp = -radius * w;
                    for (i = -radius; i <= radius; i++) {
                        yi = Math.max(0, yp) + x;
        
                        sir = stack[i + radius];
        
                        sir[0] = r[yi];
                        sir[1] = g[yi];
                        sir[2] = b[yi];
        
                        rbs = r1 - Math.abs(i);
        
                        rsum += r[yi] * rbs;
                        gsum += g[yi] * rbs;
                        bsum += b[yi] * rbs;
        
                        if (i > 0) {
                            rinsum += sir[0];
                            ginsum += sir[1];
                            binsum += sir[2];
                        } else {
                            routsum += sir[0];
                            goutsum += sir[1];
                            boutsum += sir[2];
                        }
        
                        if (i < hm) {
                            yp += w;
                        }
                    }
                    yi = x;
                    stackpointer = radius;
                    for (y = 0; y < h; y++) {
                        // Preserve alpha channel: ( 0xff000000 & pix[yi] )
                        pix[yi] = ( 0xff000000 & pix[yi] ) | ( dv[rsum] << 16 ) | ( dv[gsum] << 8 ) | dv[bsum];
        
                        rsum -= routsum;
                        gsum -= goutsum;
                        bsum -= boutsum;
        
                        stackstart = stackpointer - radius + div;
                        sir = stack[stackstart % div];
        
                        routsum -= sir[0];
                        goutsum -= sir[1];
                        boutsum -= sir[2];
        
                        if (x == 0) {
                            vmin[y] = Math.min(y + r1, hm) * w;
                        }
                        p = x + vmin[y];
        
                        sir[0] = r[p];
                        sir[1] = g[p];
                        sir[2] = b[p];
        
                        rinsum += sir[0];
                        ginsum += sir[1];
                        binsum += sir[2];
        
                        rsum += rinsum;
                        gsum += ginsum;
                        bsum += binsum;
        
                        stackpointer = (stackpointer + 1) % div;
                        sir = stack[stackpointer];
        
                        routsum += sir[0];
                        goutsum += sir[1];
                        boutsum += sir[2];
        
                        rinsum -= sir[0];
                        ginsum -= sir[1];
                        binsum -= sir[2];
        
                        yi += w;
                    }
                }
        
                Log.e("pix", w + " " + h + " " + pix.length);
                bitmap.setPixels(pix, 0, w, 0, 0, w, h);
        
                return (bitmap);
            }
        
            public class FadeView extends FrameLayout {
                private long mFadeDelay = 1000;
                private ImageView mFirst;
                private ImageView mSecond;
                private boolean mFirstShowing;
        
                public FadeView(Context context) {
                    super(context);
                    init(context);
                }
        
                public FadeView(Context context, AttributeSet attrs) {
                    super(context, attrs);
                    init(context);
                }
        
                public FadeView(Context context, AttributeSet attrs, int defStyle) {
                    super(context, attrs, defStyle);
                    init(context);
                }
        
                private void init(Context c){
                    mFirst = new ImageView(c);
                    mSecond = new ImageView(c);
        
                    mFirst.setAlpha(1.0f);
                    mSecond.setAlpha(0.0f);
        
                    mFirstShowing = true;
        
                    addView(mFirst);
                    addView(mSecond);
                }
        
                public void setFadeDelay(long fadeDelay) {
                    mFadeDelay = fadeDelay;
                }
        
                public void ShowImage(Drawable d){
                    if(mFirstShowing){
                        mSecond.setImageDrawable(d);
                        mSecond.animate().alpha(1.0f).setDuration(mFadeDelay);
                        mFirst.animate().alpha(0.0f).setDuration(mFadeDelay);
                    }else {
                        mFirst.setImageDrawable(d);
                        mSecond.animate().alpha(0.0f).setDuration(mFadeDelay);
                        mFirst.animate().alpha(1.0f).setDuration(mFadeDelay);
                    }
        
                    mFirstShowing = !mFirstShowing;
                }
            }
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
        
                final FadeView fw = new FadeView(this);
                setContentView(fw);
        
                fw.setOnClickListener(new View.OnClickListener() {
        
                    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
                    Bitmap blurredBitmap = blur(bitmap, 100);
        
                    Drawable d1 = new BitmapDrawable(getResources(), blurredBitmap);
                    Drawable d2 = getResources().getDrawable(R.drawable.image);
                    boolean flag;
        
                    @Override
                    public void onClick(View view) {
                        if(flag){
                            fw.ShowImage(d1);
                        }else {
                            fw.ShowImage(d2);
                        }
                        flag = !flag;
                    }
                });
            }
        
        }
        

        注意:交叉淡入淡出代码取自:Source(点击动画)

        我能想到的另一种方法是使用 JQuery 并为 WebView 内的模糊设置动画。

        【讨论】:

          【解决方案5】:

          我不会用代码过多地延长我的答案,因为老实说我没有它,但我会尝试指出您必须考虑的关键事项以及一些有用的链接。

          一、方法:

          • 尽可能快地模糊
          • 缓存模糊结果
          • 交叉淡入淡出

          尽可能快地模糊:

          您的算法看起来非常好,我相信它确实产生了很好的效果,但实际情况是它在 Java VM 中以单线程运行。使用 RenderScript,您肯定会获得更好的性能。这是因为 RenderScript 会自动将渲染过程扩展到多处理器和 GPU。

          它的基本代码如下,直接取自android-developers.blogspot.com:

          RenderScript rs = RenderScript.create(theActivity);
          ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(mRS, Element.U8_4(rs));;
          Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
          Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
          theIntrinsic.setRadius(25.f);
          theIntrinsic.setInput(tmpIn);
          theIntrinsic.forEach(tmpOut);
          tmpOut.copyTo(outputBitmap);
          

          缓存模糊的结果:

          那是因为模糊需要时间。对此也会有很多记忆影响,您必须仔细观察。在回收视图和内容的滚动列表中,您肯定无法很好地做到这一点。一个提示可能是使用 Picasso 库 (LINK) 并处理您的线程。像这样的:

          Picasso
             .with(context)
             .load(/* asset/res/file/url */)
             .transform(new BlurTransformation(value))
             .into(target);
          
          // The transform method is automatically called by Picasso in a background thread
          public class BlurTransformation implements com.squareup.picasso.Transformation {
              private final float radius;
          
              // radius is corner radii in dp
              public BlurTransformation(final float radius) {
                  this.radius = radius;
              }
          
              @Override
              public Bitmap transform(final Bitmap source) {
                 // do the transformation and return it here
              }
          
              @Override
              public String key() {
                  return "blur"+Float.toString(radius);
              }
          }
          
          // you can also use this to get it instantly
          Picasso... all the code... .get();
          

          交叉淡入淡出:

          在这里,您可以在性能和美观之间取得平衡。现实情况是,如果不为每一步实际渲染每一帧,真实动画是不可能的,但通过几个关键帧之间的交叉淡入淡出,您可以获得很好的效果。

          您将使用多少关键帧取决于您想要的性能、设备上的可用内存量等。

          如果您只需要 2 个关键帧(1 个不模糊,1 个完全模糊)就可以了,您可以对其应用 TransitionDrawable。如果您想要更精细的效果,则必须创建一系列交叉淡入淡出过渡,或者可能创建自己的自定义可绘制对象。

          只有 2 个关键帧,您可以在 Yahoo Weather app 上查看示例,如果您想查看带有几个关键帧的示例,请查看 Muzei live wallpaper。

          非常有用的链接*

          在以下链接中,您将看到 Muzei 的创建者(Roman Nurik,他也是 Google 的一名 Android 工程师)关于他如何实现关键帧的精彩讨论,为什么这是唯一的方法这样做,为什么,虽然代码更复杂,但它最终会产生更漂亮的结果:(短版)https://plus.google.com/+RomanNurik/posts/2sTQ1X2Cb2Z(完整版)https://medium.com/@romannurik/serendipitous-ideas-3a1721a6f716

          此链接是 Muzei 动态壁纸的源代码,您可以在其中查看他如何计算关键帧并为壁纸设置动画:https://github.com/romannurik/muzei

          祝你好运,编码愉快!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-01-03
            • 2019-10-30
            • 2011-01-17
            • 1970-01-01
            • 2014-06-19
            • 2017-07-06
            相关资源
            最近更新 更多