我想在我的应用程序中显示动画GIF图像。 正如我发现Android本身难以支持动画GIF一样。
但是,它可以使用AnimationDrawable显示动画:
Develop > Guides > Images & Graphics > Drawables Overview
该示例使用在应用程序资源中保存为框架的动画,但我需要的是直接显示动画gif。
我的计划是将动画GIF分解为帧并将每个帧添加为可绘制到AnimationDrawable。
有谁知道如何从动画GIF中提取帧并将每个帧转换为Drawable?
答案 0 :(得分:185)
Android实际上可以使用android.graphics.Movie类解码和显示动画GIF。
这没有太多记录,但在SDK Reference。此外,它在Samples in ApiDemos in BitmapDecode示例中使用了一些动画标记。
答案 1 :(得分:48)
<强>更新强>
使用滑行:
dependencies {
implementation 'com.github.bumptech.glide:glide:4.0.0'
}
用法:
Glide.with(context).load(GIF_URI).into(new GlideDrawableImageViewTarget(IMAGE_VIEW));
答案 2 :(得分:28)
还把(main / assets / htmls / name.gif)[用这个html调整到大小]
<html style="margin: 0;">
<body style="margin: 0;">
<img src="name.gif" style="width: 100%; height: 100%" />
</body>
</html>
在你的Xml中声明例如这样(main / res / layout / name.xml):[你定义大小,例如]
<WebView
android:layout_width="70dp"
android:layout_height="70dp"
android:id="@+id/webView"
android:layout_gravity="center_horizontal" />
你的Activity中的将下一个代码放在onCreate
中web = (WebView) findViewById(R.id.webView);
web.setBackgroundColor(Color.TRANSPARENT); //for gif without background
web.loadUrl("file:///android_asset/htmls/name.html");
如果您想要动态加载,则必须使用数据加载webview:
// or "[path]/name.gif" (e.g: file:///android_asset/name.gif for resources in asset folder), and in loadDataWithBaseURL(), you don't need to set base URL, on the other hand, it's similar to loadData() method.
String gifName = "name.gif";
String yourData = "<html style=\"margin: 0;\">\n" +
" <body style=\"margin: 0;\">\n" +
" <img src=" + gifName + " style=\"width: 100%; height: 100%\" />\n" +
" </body>\n" +
" </html>";
// Important to add this attribute to webView to get resource from outside.
webView.getSettings().setAllowFileAccess(true);
// Notice: should use loadDataWithBaseURL. BaseUrl could be the base url such as the path to asset folder, or SDCard or any other path, where your images or the other media resides related to your html
webView.loadDataWithBaseURL("file:///android_asset/", yourData, "text/html", "utf-8", null);
// Or if you want to load image from SD card or where else, here is the idea.
String base = Environment.getExternalStorageDirectory().getAbsolutePath().toString();
webView.loadDataWithBaseURL(base + '/', yourData, "text/html", "utf-8", null);
建议:使用静态图片更好地加载gif以获取更多信息,请查看https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html
是的,我希望你能帮忙。
答案 3 :(得分:21)
我在将 gif 动画分割成帧之前解决了这个问题,然后将其保存到手机中,因此我不必在Android中处理它。
然后我将每一帧下载到手机上,从中创建Drawable,然后创建 AnimationDrawable - 非常类似于我的问题中的示例
答案 4 :(得分:16)
我发现了一种非常简单的方法,这里有一个简单的工作示例
在开始工作之前,在代码中有一些要做的事情
以下
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceStated);
setContentView(new MYGIFView());
}
}
只需替换
setContentView(new MYGIFView());
在
setContentView(new MYGIFView(this));
AND IN
public GIFView(Context context) {
super(context);
提供您自己的gif动画文件
is = context.getResources().openRawResource(R.drawable.earth);
movie = Movie.decodeStream(is);
}
取代第一线
public MYGIFView(Context context) {
根据班级名称......
完成这些小改动后,它应该像我一样......希望这个帮助
答案 5 :(得分:9)
我很难让Android动画gif工作。我只跟着两个工作:
WebView工作正常并且非常简单,但问题是它会使视图加载速度变慢,并且应用程序在一秒左右的时间内无响应。我不喜欢那样。所以我尝试了不同的方法(DID NOT WORK):
我和Ion
来回徘徊;最后,我有它的工作,它真的很快: - )
Ion.with(imgView)
.error(R.drawable.default_image)
.animateGif(AnimateGifMode.ANIMATE)
.load("file:///android_asset/animated.gif");
答案 6 :(得分:9)
在Android上显示动画GIF的方法:
https://github.com/koral--/android-gif-drawable - 解码器在C中实现,因此非常有效。
https://code.google.com/p/giffiledecoder - 解码器以Java实现,因此更容易使用。即使是大文件,效率仍然相当高。
您还可以找到许多基于GifDecoder类的库。这也是一个基于Java的解码器,但它的工作原理是将整个文件加载到内存中,因此它只适用于小文件。
答案 7 :(得分:8)
<强> Glide
强>
适用于Android的Image Loader Library,由Google推荐。
滑翔有什么,但毕加索没有
将GIF动画加载到简单的ImageView的功能可能是Glide最有趣的功能。是的,你不能用毕加索做到这一点。 一些重要的链接 -
答案 8 :(得分:7)
使用ImageViewEx,一个使用gif的库就像使用ImageView
一样简单。
答案 9 :(得分:6)
试试这个,下面是代码显示进度条中的gif文件
loading_activity.xml(在布局文件夹中)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff" >
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/custom_loading"
android:visibility="gone" />
</RelativeLayout>
custom_loading.xml(在可绘制文件夹中)
这里我把black_gif.gif(在drawable文件夹中),你可以把你自己的gif放在这里
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/black_gif"
android:pivotX="50%"
android:pivotY="50%" />
LoadingActivity.java(在res文件夹中)
public class LoadingActivity extends Activity {
ProgressBar bar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loading);
bar = (ProgressBar) findViewById(R.id.progressBar);
bar.setVisibility(View.VISIBLE);
}
}
答案 10 :(得分:6)
答案 11 :(得分:5)
我已经成功使用了within this article提议的解决方案,这是一个名为GifMovieView
的类,它会呈现一个View
,然后可以显示或添加到特定的ViewGroup
。查看指定文章第2部分和第3部分中介绍的其他方法。
这种方法的唯一缺点是对电影的抗锯齿效果不是那么好(必须是使用“阴暗”Android Movie
类的副作用)。然后,最好在动画GIF中将背景设置为纯色。
答案 12 :(得分:4)
Glide 4.6
<强> 1。加载gif
GlideApp.with(context)
.load(R.raw.gif) // or url
.into(imageview);
<强> 2。获取文件对象
GlideApp.with(context)
.asGif()
.load(R.raw.gif) //or url
.into(new SimpleTarget<GifDrawable>() {
@Override
public void onResourceReady(@NonNull GifDrawable resource, @Nullable Transition<? super GifDrawable> transition) {
resource.start();
//resource.setLoopCount(1);
imageView.setImageDrawable(resource);
}
});
答案 13 :(得分:4)
答案 14 :(得分:4)
关于BitmapDecode示例的一些想法......基本上它使用了android.graphics中的古老而无特征的Movie类。 在最近的API版本中,您需要关闭硬件加速as described here。否则,这对我来说是分裂的。
<activity
android:hardwareAccelerated="false"
android:name="foo.GifActivity"
android:label="The state of computer animation 2014">
</activity>
这是仅使用GIF部分缩短的BitmapDecode示例。你必须制作自己的小部件(视图)并自己绘制它。不像ImageView那么强大。
import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.os.*;
import android.view.View;
public class GifActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new GifView(this));
}
static class GifView extends View {
Movie movie;
GifView(Context context) {
super(context);
movie = Movie.decodeStream(
context.getResources().openRawResource(
R.drawable.some_gif));
}
@Override
protected void onDraw(Canvas canvas) {
if (movie != null) {
movie.setTime(
(int) SystemClock.uptimeMillis() % movie.duration());
movie.draw(canvas, 0, 0);
invalidate();
}
}
}
}
可以在this fine tutorial中找到另外两种方法,一种是使用ImageView另一种是使用WebView。 ImageView方法使用来自Google Code的Apache许可android-gifview。
答案 15 :(得分:2)
在src文件夹下创建一个名为“ Utils”的程序包,并创建一个名为“ GifImageView”的类
public class GifImageView extends View {
private InputStream mInputStream;
private Movie mMovie;
private int mWidth, mHeight;
private long mStart;
private Context mContext;
public GifImageView(Context context) {
super(context);
this.mContext = context;
}
public GifImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public GifImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
if (attrs.getAttributeName(1).equals("background")) {
int id = Integer.parseInt(attrs.getAttributeValue(1).substring(1));
setGifImageResource(id);
}
}
private void init() {
setFocusable(true);
mMovie = Movie.decodeStream(mInputStream);
mWidth = mMovie.width();
mHeight = mMovie.height();
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mWidth, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
long now = SystemClock.uptimeMillis();
if (mStart == 0) {
mStart = now;
}
if (mMovie != null) {
int duration = mMovie.duration();
if (duration == 0) {
duration = 1000;
}
int relTime = (int) ((now - mStart) % duration);
mMovie.setTime(relTime);
mMovie.draw(canvas, 0, 0);
invalidate();
}
}
public void setGifImageResource(int id) {
mInputStream = mContext.getResources().openRawResource(id);
init();
}
public void setGifImageUri(Uri uri) {
try {
mInputStream = mContext.getContentResolver().openInputStream(uri);
init();
} catch (FileNotFoundException e) {
Log.e("GIfImageView", "File not found");
}
}
}
现在在MainActivity中定义GifImageView 文件:src / activity / MainActivity.class
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GifImageView gifImageView = (GifImageView) findViewById(R.id.GifImageView);
gifImageView.setGifImageResource(R.drawable.smartphone_drib);
}
}
现在的UI部件 文件:res / layout / activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:gravity="center"
android:background="#111E39"
tools:context=".Activity.MainActivity">
<com.android.animatedgif.Utils.GifImageView
android:id="@+id/GifImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
资源代码:Android example
答案 16 :(得分:2)
将其放入WebView,它必须能够正确显示它,因为默认浏览器支持gif文件。 (Froyo +,如果我没有记错的话)
答案 17 :(得分:2)
// ImageView from layout
val ima : ImageView = findViewById(R.id.img_gif)
// create AnimatedDrawable
val decodedAnimation = ImageDecoder.decodeDrawable(
// create ImageDecoder.Source object
ImageDecoder.createSource(resources, R.drawable.tenor))
// set the drawble as image source of ImageView
ima.setImageDrawable(decodedAnimation)
// play the animation
(decodedAnimation as? AnimatedImageDrawable)?.start()
XML代码,添加一个ImageView
<ImageView
android:id="@+id/img_gif"
android:background="@drawable/ic_launcher_background" <!--Default background-->
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_width="200dp"
android:layout_height="200dp" />
AnimatedImageDrawable
是Drawable的子元素,由ImageDecoder.decodeDrawable
ImageDecoder.decodeDrawable
进一步需要由ImageDecoder.Source
创建的ImageDecoder.createSource
实例。
ImageDecoder.createSource
只能使用source作为名称,使用ByteBuffer,File,resourceId,URI,ContentResolver创建源对象,并使用它以AnimatedImageDrawable
的形式创建Drawable
(多态调用)< / p>
static ImageDecoder.Source createSource(AssetManager assets, String fileName)
static ImageDecoder.Source createSource(ByteBuffer buffer)
static ImageDecoder.Source createSource(File file)
static ImageDecoder.Source createSource(Resources res, int resId)
static ImageDecoder.Source createSource(ContentResolver cr, Uri uri)
注意:您也可以使用ImageDecoder#decodeBitmap创建Bitmap
。
输出:
AnimatedDrawable also supports resizing, frame and color manipulation
答案 18 :(得分:2)
将动画GIF加载到我们的Android应用中有两种选择
1)使用Glide将gif加载到ImageView
。
String urlGif = "https://cdn.dribbble.com/users/263558/screenshots/1337078/dvsd.gif";
//add Glide implementation into the build.gradle file.
ImageView imageView = (ImageView)findViewById(R.id.imageView);
Uri uri = Uri.parse(urlGif);
Glide.with(getApplicationContext()).load(uri).into(imageView);
2)使用html将gif加载到WebView
使用.gif文件的地址创建html:
<html style="margin: 0;">
<body style="margin: 0;">
<img src="https://..../myimage.gif" style="width: 100%; height: 100%" />
</body>
</html>
将此文件存储到assets目录中:
将此html加载到应用程序的WebView中:
WebView webView = (WebView)findViewById(R.id.webView);
webView = (WebView) findViewById(R.id.webView);
webView.loadUrl("file:///android_asset/html/webpage_gif.html");
答案 19 :(得分:1)
我认为处理gif文件的更好的库是this one: by koral
使用它,我很成功,这个图书馆专门用于GIF'S;但毕加索和滑翔是通用图像框架的地方;所以我认为这个库的开发人员完全专注于gif文件
答案 20 :(得分:1)
使用壁画。以下是如何做到这一点:
http://frescolib.org/docs/animations.html
这里是样本的回购:
https://github.com/facebook/fresco/tree/master/samples/animation
当心壁画不支持包装内容!
答案 21 :(得分:0)
如果你想使用 Glide 加载 gif:
Glide.with(this)
.asGif()
.load(R.raw.onboarding_layers) //Your gif resource
.apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE))
.listener(new RequestListener<GifDrawable>() {
@Override
public boolean onLoadFailed(@Nullable @org.jetbrains.annotations.Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
resource.setLoopCount(1);
return false;
}
})
.into((ImageView) view.findViewById(R.id.layer_icons));
答案 22 :(得分:0)
答案 23 :(得分:0)
直接从URL到应用布局显示动画GIF的简便方法是使用WebView类。
第1步: 在您的布局XML中
<WebView
android:id="@+id/webView"
android:layout_width="50dp"
android:layout_height="50dp"
/>
第2步:在您的活动中
WebView wb;
wb = (WebView) findViewById(R.id.webView);
wb.loadUrl("https://.......);
第3步:在您的Manifest.XML中进行互联网许可
<uses-permission android:name="android.permission.INTERNET" />
第4步:如果您想让GIF背景透明并使GIF适合您的版式
wb.setBackgroundColor(Color.TRANSPARENT);
wb.getSettings().setLoadWithOverviewMode(true);
wb.getSettings().setUseWideViewPort(true);
答案 24 :(得分:0)
为了节省资源,有滑翔库。 不知道为什么要使用其他任何东西,尤其是 webview 只显示图像。 Glide 是一个完美且简单的库,它可以从 gif 中准备可绘制动画并将其直接放入 imageview。 gifdrawable 处理动画本身的逻辑。 Gif 已经 lzw 压缩了动画的原始 rgb 数据。 没有理由复杂的使用webview,管理更多的文件在app中只显示一个gif文件。
答案 25 :(得分:0)
最简单的方法 - 可以考虑以下代码
我们可以利用Imageview setImageResource,参考下面的代码。
如果你有gif的多个分割图像,下面的代码可用于显示像gif incase的图像。只需将gif从在线工具拆分为单独的png,然后将图像放入drawable中,如下面的顺序
image_1.png,image_2.png等
让处理程序动态更改图像。
int imagePosition = 1;
Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
updateImage();
}
};
public void updateImage() {
appInstance.runOnUiThread(new Runnable() {
@Override
public void run() {
int resId = getResources().getIdentifier("image_" + imagePosition, "drawable", appInstance.getPackageName());
gifImageViewDummy.setImageResource(resId);
imagePosition++;
//Consider you have 30 image for the anim
if (imagePosition == 30) {
//this make animation play only once
handler.removeCallbacks(runnable);
} else {
//You can define your own time based on the animation
handler.postDelayed(runnable, 50);
}
//to make animation to continue use below code and remove above if else
// if (imagePosition == 30)
//imagePosition = 1;
// handler.postDelayed(runnable, 50);
//
}
});
}
答案 26 :(得分:0)
我通过在帧中拆分gif并使用标准的android动画来解决这个问题
答案 27 :(得分:0)
我在应用中展示GIF的方式。我扩展了ImageView,以便人们可以自由使用它的属性。它可以显示来自url或assets目录的gif。 该库还使扩展类很容易从它继承并扩展它以支持不同的方法来初始化gif。
https://github.com/Gavras/GIFView
github页面上有一个小指南。
它也发布在Android Arsenal上:
https://android-arsenal.com/details/1/4947
使用示例:
来自XML:
<com.whygraphics.gifview.gif.GIFView xmlns:gif_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_activity_gif_vie"
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="center"
gif_view:gif_src="url:http://pop.h-cdn.co/assets/16/33/480x264/gallery-1471381857-gif-season-2.gif" />
在活动中:
GIFView mGifView = (GIFView) findViewById(R.id.main_activity_gif_vie);
mGifView.setOnSettingGifListener(new GIFView.OnSettingGifListener() {
@Override
public void onSuccess(GIFView view, Exception e) {
Toast.makeText(MainActivity.this, "onSuccess()", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(GIFView view, Exception e) {
}
});
以编程方式设置gif:
mGifView.setGifResource("asset:gif1");
答案 28 :(得分:0)
首先,Android浏览器应支持动画GIF。如果没有,那就是一个错误!看一下问题跟踪器。
如果您在浏览器之外显示这些动画GIF,则可能是另一回事。要做你想要的就需要支持解码动画GIF的外部库。
第一个调用端口是查看Java2D或JAI(Java高级成像)API,但如果Android Dalvik支持您应用程序中的这些库,我会非常惊讶。
答案 29 :(得分:0)
类似于@Leonti所说的,但更深入一点:
我为解决同样的问题所做的是打开GIMP,隐藏除了一个之外的所有图层,将其导出为自己的图像,然后隐藏该图层并取消隐藏下一个等等,直到我有单独的资源文件每一个人。然后我可以将它们用作AnimationDrawable XML文件中的框架。
答案 30 :(得分:-1)
您可以使用此链接中的GifAnimationDrawable库 - https://github.com/Hipmob/gifanimateddrawable,并将任何gif转换为AnimationDrawable。享受:)
答案 31 :(得分:-9)
public class Test extends GraphicsActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
private static class SampleView extends View {
private Bitmap mBitmap;
private Bitmap mBitmap2;
private Bitmap mBitmap3;
private Bitmap mBitmap4;
private Drawable mDrawable;
private Movie mMovie;
private long mMovieStart;
// Set to false to use decodeByteArray
private static final boolean DECODE_STREAM = true;
private static byte[] streamToBytes(InputStream is) {
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int len;
try {
while ((len = is.read(buffer)) >= 0) {
os.write(buffer, 0, len);
}
} catch (java.io.IOException e) {
}
return os.toByteArray();
}
public SampleView(Context context) {
super(context);
setFocusable(true);
java.io.InputStream is;
is = context.getResources().openRawResource(R.drawable.icon);
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bm;
opts.inJustDecodeBounds = true;
bm = BitmapFactory.decodeStream(is, null, opts);
// now opts.outWidth and opts.outHeight are the dimension of the
// bitmap, even though bm is null
opts.inJustDecodeBounds = false; // this will request the bm
opts.inSampleSize = 4; // scaled down by 4
bm = BitmapFactory.decodeStream(is, null, opts);
mBitmap = bm;
// decode an image with transparency
is = context.getResources().openRawResource(R.drawable.icon);
mBitmap2 = BitmapFactory.decodeStream(is);
// create a deep copy of it using getPixels() into different configs
int w = mBitmap2.getWidth();
int h = mBitmap2.getHeight();
int[] pixels = new int[w * h];
mBitmap2.getPixels(pixels, 0, w, 0, 0, w, h);
mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h,
Bitmap.Config.ARGB_8888);
mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h,
Bitmap.Config.ARGB_4444);
mDrawable = context.getResources().getDrawable(R.drawable.icon);
mDrawable.setBounds(150, 20, 300, 100);
is = context.getResources().openRawResource(R.drawable.animated_gif);
if (DECODE_STREAM) {
mMovie = Movie.decodeStream(is);
} else {
byte[] array = streamToBytes(is);
mMovie = Movie.decodeByteArray(array, 0, array.length);
}
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFCCCCCC);
Paint p = new Paint();
p.setAntiAlias(true);
canvas.drawBitmap(mBitmap, 10, 10, null);
canvas.drawBitmap(mBitmap2, 10, 170, null);
canvas.drawBitmap(mBitmap3, 110, 170, null);
canvas.drawBitmap(mBitmap4, 210, 170, null);
mDrawable.draw(canvas);
long now = android.os.SystemClock.uptimeMillis();
if (mMovieStart == 0) { // first time
mMovieStart = now;
}
if (mMovie != null) {
int dur = mMovie.duration();
if (dur == 0) {
dur = 1000;
}
int relTime = (int) ((now - mMovieStart) % dur);
mMovie.setTime(relTime);
mMovie.draw(canvas, getWidth() - mMovie.width(), getHeight()
- mMovie.height());
invalidate();
}
}
}
}
class GraphicsActivity extends Activity {
// set to true to test Picture
private static final boolean TEST_PICTURE = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void setContentView(View view) {
if (TEST_PICTURE) {
ViewGroup vg = new PictureLayout(this);
vg.addView(view);
view = vg;
}
super.setContentView(view);
}
}
class PictureLayout extends ViewGroup {
private final Picture mPicture = new Picture();
public PictureLayout(Context context) {
super(context);
}
public PictureLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void addView(View child) {
if (getChildCount() > 1) {
throw new IllegalStateException(
"PictureLayout can host only one direct child");
}
super.addView(child);
}
@Override
public void addView(View child, int index) {
if (getChildCount() > 1) {
throw new IllegalStateException(
"PictureLayout can host only one direct child");
}
super.addView(child, index);
}
@Override
public void addView(View child, LayoutParams params) {
if (getChildCount() > 1) {
throw new IllegalStateException(
"PictureLayout can host only one direct child");
}
super.addView(child, params);
}
@Override
public void addView(View child, int index, LayoutParams params) {
if (getChildCount() > 1) {
throw new IllegalStateException(
"PictureLayout can host only one direct child");
}
super.addView(child, index, params);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int count = getChildCount();
int maxHeight = 0;
int maxWidth = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
maxWidth += getPaddingLeft() + getPaddingRight();
maxHeight += getPaddingTop() + getPaddingBottom();
Drawable drawable = getBackground();
if (drawable != null) {
maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
}
setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
resolveSize(maxHeight, heightMeasureSpec));
}
private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx,
float sy) {
canvas.save();
canvas.translate(x, y);
canvas.clipRect(0, 0, w, h);
canvas.scale(0.5f, 0.5f);
canvas.scale(sx, sy, w, h);
canvas.drawPicture(mPicture);
canvas.restore();
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight()));
mPicture.endRecording();
int x = getWidth() / 2;
int y = getHeight() / 2;
if (false) {
canvas.drawPicture(mPicture);
} else {
drawPict(canvas, 0, 0, x, y, 1, 1);
drawPict(canvas, x, 0, x, y, -1, 1);
drawPict(canvas, 0, y, x, y, 1, -1);
drawPict(canvas, x, y, x, y, -1, -1);
}
}
@Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
location[0] = getLeft();
location[1] = getTop();
dirty.set(0, 0, getWidth(), getHeight());
return getParent();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = super.getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final int childLeft = getPaddingLeft();
final int childTop = getPaddingTop();
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(),
childTop + child.getMeasuredHeight());
}
}
}
}