Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/183.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否可以在android中将动画gif文件设置为实时壁纸?_Android - Fatal编程技术网

是否可以在android中将动画gif文件设置为实时壁纸?

是否可以在android中将动画gif文件设置为实时壁纸?,android,Android,我是Android平台的新手。我希望开发一个实时壁纸应用程序。当我在搜索引擎中被搜索到这一点时,他们中的许多人创建了一张实时壁纸作为他们的代码(使用SurfaceView和Canvas),我对此不太清楚。这里我的疑问是,任何可以将.gif图像设置为实时壁纸的这是基本的壁纸服务(如实时壁纸教程中提供的)被黑客攻击以显示动画gif 首先-创建一个项目并将清单设置为实时墙纸。 然后-下载一个gif,如下图所示 将该gif保存在项目的res/raw/nyan.gif中。 创建实时墙纸服务,如本例所示。

我是Android平台的新手。我希望开发一个实时壁纸应用程序。当我在搜索引擎中被搜索到这一点时,他们中的许多人创建了一张实时壁纸作为他们的代码(使用
SurfaceView
Canvas
,我对此不太清楚。这里我的疑问是,任何可以将.gif图像设置为实时壁纸的

这是基本的壁纸服务(如实时壁纸教程中提供的)被黑客攻击以显示动画gif

首先-创建一个项目并将清单设置为实时墙纸。
然后-下载一个gif,如下图所示

将该gif保存在项目的
res/raw/nyan.gif
中。
创建实时墙纸服务,如本例所示。

public class NyanNyanService extends WallpaperService {
    static final String TAG = "NYAN";
    static final Handler mNyanHandler = new Handler();

    /**
     * @see android.service.wallpaper.WallpaperService#onCreate()
     */
    @Override
    public void onCreate() {
        super.onCreate();
    }

    /**
     * @see android.service.wallpaper.WallpaperService#onCreateEngine()
     */
    @Override
    public Engine onCreateEngine() {
        try {
            return new NyanEngine();
        } catch (IOException e) {
            Log.w(TAG, "Error creating NyanEngine", e);
            stopSelf();
            return null;
        }
    }

    class NyanEngine extends Engine {
        private final Movie mNyan;
        private final int mNyanDuration;
        private final Runnable mNyanNyan;
        float mScaleX;
        float mScaleY;
        int mWhen;
        long mStart;

        NyanEngine() throws IOException {
            InputStream is = getResources().openRawResource(R.raw.nyan);
            if (is != null) {
                try {
                    mNyan = Movie.decodeStream(is);
                    mNyanDuration = mNyan.duration();
                } finally {
                    is.close();
                }
            } else {
                throw new IOException("Unable to open R.raw.nyan");
            }

            mWhen = -1;
            mNyanNyan = new Runnable() {
                public void run() {
                    nyan();
                }
            };
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            mNyanHandler.removeCallbacks(mNyanNyan);
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            super.onVisibilityChanged(visible);
            if (visible) {
                nyan();
            } else {
                mNyanHandler.removeCallbacks(mNyanNyan);
            }
        }

        @Override
        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            super.onSurfaceChanged(holder, format, width, height);
            mScaleX = width / (1f * mNyan.width());
            mScaleY = height / (1f * mNyan.height());
            nyan();
        }

        @Override
        public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep,
                float yOffsetStep, int xPixelOffset, int yPixelOffset) {
            super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset);
            nyan();
        }

        void nyan() {
            tick();
            SurfaceHolder surfaceHolder = getSurfaceHolder();
            Canvas canvas = null;
            try {
                canvas = surfaceHolder.lockCanvas();
                if (canvas != null) {
                    nyanNyan(canvas);
                }
            } finally {
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
            mNyanHandler.removeCallbacks(mNyanNyan);
            if (isVisible()) {
                mNyanHandler.postDelayed(mNyanNyan, 1000L/25L);
            }
        }

        void tick() {
            if (mWhen == -1L) {
                mWhen = 0;
                mStart = SystemClock.uptimeMillis();
            } else {
                long mDiff = SystemClock.uptimeMillis() - mStart;
                mWhen = (int) (mDiff % mNyanDuration);
            }
        }

        void nyanNyan(Canvas canvas) {
            canvas.save();
            canvas.scale(mScaleX, mScaleY);
            mNyan.setTime(mWhen);
            mNyan.draw(canvas, 0, 0);
            canvas.restore();
        }
    }
}
这将基本上缩放nyan-nyan猫以适应屏幕,并永久地为其设置动画

实时墙纸清单看起来有点像这样(此示例不包含配置活动):

见本文:

Jens回答使用“Movie”类,但在android api 28中不推荐使用Movie类

因此,当api>=28时,我使用AnimatedImageDrawable

像Jens answer一样设置实时墙纸,我更改墙纸服务代码:

墙纸服务:动漫墙纸

public class AnimWallpaper extends WallpaperService {
    @Override
    public Engine onCreateEngine() {
        return new CustomEngine();
    }

    class CustomEngine extends Engine {
        UseAnim useAnim;

        public CustomEngine() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                useAnim = new UseAnim(getApplicationContext(), getSurfaceHolder(), R.raw.gif2);
            }
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            super.onVisibilityChanged(visible);
            if (visible) {
                useAnim.restart();
            } else {
                useAnim.stop();
            }
        }

        @Override
        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            super.onSurfaceChanged(holder, format, width, height);
            useAnim.updateScaleAndPadding2(width, height);
            useAnim.restart();
        }


        @Override
        public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) {
            super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset);
            useAnim.restart();
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            useAnim.stop();
        }
    }

}
UseAnim

class UseAnim {
    SurfaceHolder holder;
    Runnable startRunnable;
    AnimatedImageDrawable gif;
    float fps = 60;
    Handler handler = new Handler();

    @RequiresApi(api = Build.VERSION_CODES.P)
    public UseAnim(Context ctx, SurfaceHolder holder, int gifResId) {
        this.holder = holder;
        final ImageDecoder.Source src = ImageDecoder.createSource(ctx.getResources(), gifResId);
        startRunnable = new Runnable() {
            @Override
            public void run() {
                start();
            }
        };

        new Handler().post(new Runnable() {
            @Override
            public void run() {
                try {
                    UseAnim.this.gif = (AnimatedImageDrawable) ImageDecoder.decodeDrawable(src);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

                UseAnim.this.gif.start();
            }
        });
    }

    public void restart() {
        stop();
        start();
    }

    float scale = -1;

    public void start() {
        // since get gif with AnimatedImageDrawable must be in handler.post, so gif maybe null
        if (gif != null) {
            Canvas canvas = null;
            try {
                if (scale == -1) {
                    updateScaleAndPadding();
                }

                canvas = holder.lockCanvas();

                if (canvas != null) {
                    canvas.translate(horiPadding, vertiPadding);
                    canvas.scale(scale, scale);
                    gif.draw(canvas);
                }
            } finally {
                if (canvas != null) {
                    holder.unlockCanvasAndPost(canvas);
                }
            }
        }

        handler.removeCallbacks(startRunnable);
        handler.postDelayed(startRunnable, (long) (1000L / fps));
    }

    public void stop() {
        handler.removeCallbacks(startRunnable);
    }

    int horiPadding;
    int vertiPadding;

    private void updateScaleAndPadding() {
        Canvas canvas = null;
        try {
            canvas = holder.lockCanvas();
            int cw = canvas.getWidth();
            int ch = canvas.getHeight();

            updateScaleAndPadding2(cw, ch);
        } finally {
            if (canvas != null) {
                holder.unlockCanvasAndPost(canvas);
            }
        }
    }

    public void updateScaleAndPadding2(int cw, int ch) {
        if (gif != null) {
            int gifW = gif.getIntrinsicWidth();
            int gifH = gif.getIntrinsicHeight();
            if (gifW * 1f / gifH > cw * 1f / ch) {
                scale = ch * 1f / gifH;
            } else {
                scale = cw * 1f / gifW;
            }

            horiPadding = (int) ((cw - gifW * scale) / 2);
            vertiPadding = (int) ((ch - gifH * scale) / 2);
        }
    }
}

请参考@Jens:感谢您的重播,如果您有任何示例代码如何执行此操作,那么,这显示了我使用的是这样的,但是我将.gif图像设置为我的墙纸,它看起来像普通的jpeg图像。它没有执行animatedit,但屏幕上没有输出,在我的控制台中显示,cat=[android.intent.category.LAUNCHER]flg=0x10000000 cmp=test.anim/.nyanyservice}从null(pid=7019,uid=2000)开始需要android.permission.BIND\u wallphi。。。这个漂亮的bat有时超过1个gif文件,并且只使用了一个服务,当时代码没有显示太多问题,请尝试+1以获得更好的解释。我可以播放视频而不是GIF图像吗?如果是,怎么做?@peejaybee-你可以自由地做你想做的事情,不需要积分。如果你注意到低端设备或旧版本的Android(我还没有做测试来告诉我哪个是错误的)上的撕裂,检查(1)动画gif是否未优化,以及(2)所有帧的大小是否相同。在G2运行的姜饼上,现场壁纸看起来很糟糕。第1步是一个巨大的改进,但它采取了两个步骤,使它在旧手机上看起来正确。此代码有错误。当我尝试访问此命令时,我得到了崩溃NullPointerException!使用动画。更新刻度和填充2(宽度、高度)@DynoCris在我的示例中,R.raw.gif2是我的项目“raw”dir中的gif,在您的项目中不存在,您可以找到带有AnimatedImageDrawable的android文档,以了解如何使AnimatedImageDrawable显示gif。当然,我添加了这个gif文件。要启动您的代码片段,还需要执行哪些操作?使用updateScaleAndPadding2()方法修复NPE
public class AnimWallpaper extends WallpaperService {
    @Override
    public Engine onCreateEngine() {
        return new CustomEngine();
    }

    class CustomEngine extends Engine {
        UseAnim useAnim;

        public CustomEngine() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                useAnim = new UseAnim(getApplicationContext(), getSurfaceHolder(), R.raw.gif2);
            }
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            super.onVisibilityChanged(visible);
            if (visible) {
                useAnim.restart();
            } else {
                useAnim.stop();
            }
        }

        @Override
        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            super.onSurfaceChanged(holder, format, width, height);
            useAnim.updateScaleAndPadding2(width, height);
            useAnim.restart();
        }


        @Override
        public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) {
            super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset);
            useAnim.restart();
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            useAnim.stop();
        }
    }

}
class UseAnim {
    SurfaceHolder holder;
    Runnable startRunnable;
    AnimatedImageDrawable gif;
    float fps = 60;
    Handler handler = new Handler();

    @RequiresApi(api = Build.VERSION_CODES.P)
    public UseAnim(Context ctx, SurfaceHolder holder, int gifResId) {
        this.holder = holder;
        final ImageDecoder.Source src = ImageDecoder.createSource(ctx.getResources(), gifResId);
        startRunnable = new Runnable() {
            @Override
            public void run() {
                start();
            }
        };

        new Handler().post(new Runnable() {
            @Override
            public void run() {
                try {
                    UseAnim.this.gif = (AnimatedImageDrawable) ImageDecoder.decodeDrawable(src);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

                UseAnim.this.gif.start();
            }
        });
    }

    public void restart() {
        stop();
        start();
    }

    float scale = -1;

    public void start() {
        // since get gif with AnimatedImageDrawable must be in handler.post, so gif maybe null
        if (gif != null) {
            Canvas canvas = null;
            try {
                if (scale == -1) {
                    updateScaleAndPadding();
                }

                canvas = holder.lockCanvas();

                if (canvas != null) {
                    canvas.translate(horiPadding, vertiPadding);
                    canvas.scale(scale, scale);
                    gif.draw(canvas);
                }
            } finally {
                if (canvas != null) {
                    holder.unlockCanvasAndPost(canvas);
                }
            }
        }

        handler.removeCallbacks(startRunnable);
        handler.postDelayed(startRunnable, (long) (1000L / fps));
    }

    public void stop() {
        handler.removeCallbacks(startRunnable);
    }

    int horiPadding;
    int vertiPadding;

    private void updateScaleAndPadding() {
        Canvas canvas = null;
        try {
            canvas = holder.lockCanvas();
            int cw = canvas.getWidth();
            int ch = canvas.getHeight();

            updateScaleAndPadding2(cw, ch);
        } finally {
            if (canvas != null) {
                holder.unlockCanvasAndPost(canvas);
            }
        }
    }

    public void updateScaleAndPadding2(int cw, int ch) {
        if (gif != null) {
            int gifW = gif.getIntrinsicWidth();
            int gifH = gif.getIntrinsicHeight();
            if (gifW * 1f / gifH > cw * 1f / ch) {
                scale = ch * 1f / gifH;
            } else {
                scale = cw * 1f / gifW;
            }

            horiPadding = (int) ((cw - gifW * scale) / 2);
            vertiPadding = (int) ((ch - gifH * scale) / 2);
        }
    }
}