Is it possible to set an animated gif file as live wallpaper in android?

后端 未结 2 1789
时光说笑
时光说笑 2020-11-29 19:01

I\'m new to Android platform. I wish to develop a live wallpaper application. When i was searched regarding this in search Engine\'s, many of them created a

相关标签:
2条回答
  • 2020-11-29 19:50

    See this article: How to set gif as android live wallpaper - techprpr - Medium

    Jens answer use "Movie" class, but Movie class is deprecated in android api 28

    so when api >= 28, I use AnimatedImageDrawable instead

    Setup live wallpaper like Jens answer, and I change wallpaper service code:

    wallpaper service: AnimWallpaper

    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);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:55

    This is the basic wallpaper service (as supplied in the Live Wallpaper Tutorial) hacked to display an animated gif.

    First - create a project & set up your manifest as a Live wallpaper.
    Then - download a gif, like this one
       nyan nyan

    Save that gif in res/raw/nyan.gif in your project.
    Create a live wallpaper service, like shown in this example.

    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();
            }
        }
    }
    

    This will basically scale the nyan-nyan cat to fit the screen and animate it perpetually.

    A Live wallpaper manifest looks sort-of-like this (this example does not contain a configuration activity):

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="your.nyan.nyan.package"
        android:versionCode="1"
        android:versionName="1.0" >
        <uses-sdk android:minSdkVersion="10" />
        <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/application_nyan" > 
            <service 
                android:label="@string/wallpaper_nyan"
                android:name=".NyanNyanService"
                android:permission="android.permission.BIND_WALLPAPER">
                <intent-filter>
                    <action android:name="android.service.wallpaper.WallpaperService" />
                </intent-filter>
                <meta-data android:name="android.service.wallpaper" android:resource="@xml/nyan" />
            </service>
        </application>
    </manifest>
    

    The AndroidManifest.xml has a reference to a file in res/xml, in this case named "nyan.xml":

    <?xml version="1.0" encoding="utf-8"?>
    <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" />
    
    0 讨论(0)
提交回复
热议问题