How to create a simple live wallpaper using animated .gif image? I'm getting .gif image not proportioned to the screen. How to make it centercrop?
-
theres an xml property scaleType . . have you tried it? – Sanoop Surendran Mar 29 '16 at 11:43
-
and your question and title are different.. so change the title please.. – Sanoop Surendran Mar 29 '16 at 11:44
-
1I tried without using activity_main.xml file. So for .gif i couldnt use scalType programatically. – GAYATHRI KUNHIKRISHNAN Mar 29 '16 at 11:53
-
try this .. imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); – Sanoop Surendran Mar 29 '16 at 12:33
2 Answers
Your activity file
public class GIFWallpaperService extends WallpaperService {
@Override
public WallpaperService.Engine onCreateEngine() {
try {
Movie movie = Movie.decodeStream(
getResources().getAssets().open("owlinsnow.gif"));
return new GIFWallpaperEngine(movie);
}catch(IOException e){
Log.d("GIF", "Could not load asset");
return null;
}
}
private class GIFWallpaperEngine extends WallpaperService.Engine {
private final int frameDuration = 20;
private SurfaceHolder holder;
private Movie movie;
private boolean visible;
private Handler handler;
public GIFWallpaperEngine(Movie movie) {
this.movie = movie;
handler = new Handler();
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
this.holder = surfaceHolder;
}
private Runnable drawGIF = new Runnable() {
public void run() {
draw();
}
};
private void draw() {
if (visible) {
Canvas canvas = holder.lockCanvas();
canvas.save();
// Adjust size and position so that
// the image looks good on your screen
canvas.scale(2f, 2f);
movie.draw(canvas, -100, 0);
canvas.restore();
holder.unlockCanvasAndPost(canvas);
movie.setTime((int) (System.currentTimeMillis() % movie.duration()));
handler.removeCallbacks(drawGIF);
handler.postDelayed(drawGIF, frameDuration);
}
}
@Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
handler.post(drawGIF);
} else {
handler.removeCallbacks(drawGIF);
}
}
@Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(drawGIF);
}
}
}
Manifest file
<application android:allowBackup="true" android:label="@string/app_name"
android:icon="@drawable/owl" android:theme="@style/AppTheme">
<service
android:name=".GIFWallpaperService"
android:enabled="true"
android:label="Owl in Snow"
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/wallpaper" >
</meta-data>
</service>
</application>
<uses-feature
android:name="android.software.live_wallpaper"
android:required="true" >
</uses-feature>
Create xml directory under res and wallpaper.xml inside it.
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:label="GIF Wallpaper"
android:thumbnail="@drawable/owl">
</wallpaper>
Make sure you place the gif image inside assets folder. To create an asset folder click on file->New->Folder->assets

- 378
- 2
- 14
-
It works. But for different devices the image is not propotioned properly. – GAYATHRI KUNHIKRISHNAN Mar 29 '16 at 12:03
-
1istead of canvas.scale(2f, 2f); try DisplayMetrics displaymetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); int height = displaymetrics.heightPixels; int width = displaymetrics.widthPixels; – Varun Puravankara Mar 29 '16 at 12:05
-
1@VarunPuravankara The method would be useful, yes. But it would be a little complicated to use without the context being provided. Moreover the surfaceview of the screen on which we are drawing could change, like rotation or multimonitor, etc. So using the values passed by onSurfaceChanged could help. Look at my answer for clarification. – Sanved Jun 23 '17 at 16:38
In my opinion the selected answer is somewhat incomplete and not generic as it mentions hard coded values and doesn't keep in mind different screen sizes. It would be much easier to just get the values sent by onSurfaceChanged method and to use them to scale the Canvas object.
Basically, we take the ratio of the screen width to the movie(GIF) width and the ratio of the screen height to the movie height. These two variables are then used to scale the canvas to fill across the screen perfectly.
Firstly, store the width and height you get from onSurfaceChanged method globally.
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
super.onSurfaceChanged(holder, format, width, height);
this.width = width;
this.height = height;
//GLOBALLY DECLARED
}
onSurfaceChanged runs right after onCreate runs so don't worry, the values will be stored in variables width and height before they are used.
Later when you are initializing the canvas, scale it by using the ratio of the screen size to the movie size. PS - movie is a Movie object associated with the GIF we are working with.
float x = (float)width / (float)movie.width();
float y = (float)height / (float)movie.height();
canvas.scale(x,y);

- 921
- 13
- 19