poner ejecutar como java android animated-gif

java - ejecutar - Mostrar GIF animado



ejecutar gif en java (29)

@PointerNull dio una buena solución, pero no es perfecta. No funciona en algunos dispositivos con archivos grandes y muestra animaciones GIF con buggy con marcos delta en la versión pre ICS. Encontré la solución sin estos errores. Es una biblioteca con decodificación nativa para https://github.com/koral--/android-gif-drawable : https://github.com/koral--/android-gif-drawable .

Quiero mostrar imágenes GIF animadas en mi aplicación. Como descubrí la manera difícil, Android no es compatible con GIF animado de forma nativa.

Sin embargo, puede mostrar animaciones usando AnimationDrawable :

Desarrollar> Guías> Imágenes y gráficos> Resumen de dibujos

El ejemplo utiliza la animación guardada como marcos en los recursos de la aplicación, pero lo que necesito es mostrar el gif animado directamente.

Mi plan es dividir el GIF animado en cuadros y agregar cada cuadro como dibujable a AnimationDrawable.

¿Alguien sabe cómo extraer marcos de GIF animados y convertir cada uno de ellos en Drawable ?


Algo que hice para mostrar gifs en aplicaciones. Extendí ImageView para que la gente pueda usar sus atributos libremente. Puede mostrar gifs de url o del directorio de activos. La biblioteca también facilita la extensión de las clases para heredarla y extenderla para que admita diferentes métodos para inicializar el gif.

https://github.com/Gavras/GIFView

Hay una pequeña guía en la página de github.

También fue publicado en Android Arsenal:

https://android-arsenal.com/details/1/4947

Ejemplo de uso:

Desde 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" />

En la actividad:

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

Configurando el gif programáticamente:

mGifView.setGifResource("asset:gif1");


Algunas reflexiones sobre el ejemplo de BitmapDecode ... Básicamente, utiliza la antigua clase de películas pero sin rasgos distintivos de android.graphics. En las versiones de API recientes, debe desactivar la aceleración de hardware, como se describe aquí . De lo contrario, fue segregarme.

<activity android:hardwareAccelerated="false" android:name="foo.GifActivity" android:label="The state of computer animation 2014"> </activity>

Aquí está el ejemplo de BitmapDecode abreviado con solo la parte GIF. Tienes que hacer tu propio Widget (Ver) y dibujarlo por ti mismo. No es tan poderoso como un 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(); } } } }

En este excelente tutorial se pueden encontrar otros 2 métodos, uno con ImageView y otro con WebView. El método ImageView utiliza la licencia de android-gifview licencia Apache de Google Code.



Creo que la mejor biblioteca para manejar archivos gif es https://github.com/koral--/android-gif-drawable

Lo usé y tengo éxito y esta biblioteca está dedicada a GIF''S; pero donde, como picasso y glide, son marcos de imágenes de propósito general ; Así que creo que los desarrolladores de esta biblioteca se han concentrado por completo en archivos gif.


En primer lugar, el navegador de Android debe soportar GIF animados. Si no es así, entonces es un error! Echa un vistazo a los rastreadores de problemas.

Si está mostrando estos GIF animados fuera de un navegador, podría ser una historia diferente. Para hacer lo que estás pidiendo se requeriría una biblioteca externa que admita la decodificación de GIF animados.

El primer punto de contacto sería mirar la API de Java2D o JAI (Java Advanced Imaging), aunque me sorprendería mucho si Android Dalvik admitiera esas bibliotecas en su aplicación.


Encontré una manera muy fácil, con un ejemplo de trabajo agradable y simple aquí.

mostrar widget animado

Antes de ponerlo en funcionamiento, hay algunas cosas que hacer en el código.

EN EL SIGUIENTE

@Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceStated); setContentView(new MYGIFView()); } }

solo reemplaza

setContentView(new MYGIFView());

en

setContentView(new MYGIFView(this));

Y EN

public GIFView(Context context) { super(context);

Proporcione su propio archivo de animación gif

is = context.getResources().openRawResource(R.drawable.earth); movie = Movie.decodeStream(is); }

SUSTITUYA LA PRIMERA LINEA EN

public MYGIFView(Context context) {

Según el nombre de la clase ...

Después de hacer estos pequeños cambios, debería funcionar como para mí ...

espero que esto ayude


Formas de mostrar GIF animado en Android:

  • Clase de pelicula Como se mencionó anteriormente, es bastante buggy.
  • WebView. Es muy simple de usar y por lo general funciona. Pero a veces comienza a comportarse mal, y siempre está en algunos dispositivos oscuros que no tiene. Además, no puede usar varias instancias en ningún tipo de vistas de lista, porque hace cosas a su memoria. Aún así, podría considerarlo como un enfoque primario.
  • Código personalizado para decodificar gifs en mapas de bits y mostrarlos como Drawable o ImageView. Mencionaré dos bibliotecas:

https://github.com/koral--/android-gif-drawable - el decodificador se implementa en C, por lo que es muy eficiente.

https://code.google.com/p/giffiledecoder : el decodificador se implementa en Java, por lo que es más fácil trabajar con él. Aún razonablemente eficiente, incluso con archivos grandes.

También encontrarás muchas bibliotecas basadas en la clase GifDecoder. También es un decodificador basado en Java, pero funciona al cargar el archivo completo en la memoria, por lo que solo es aplicable a archivos pequeños.


Hay dos opciones para cargar gifs animados en nuestras aplicaciones de Android

1) Usando docs para cargar el gif en un 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) Usando un html para cargar el gif en un WebView

Crea el html con la dirección al archivo .gif:

<html style="margin: 0;"> <body style="margin: 0;"> <img src="https://..../myimage.gif" style="width: 100%; height: 100%" /> </body> </html>

almacenar este archivo en el directorio de activos:

Cargue este html en la vista web de su aplicación:

WebView webView = (WebView)findViewById(R.id.webView); webView = (WebView) findViewById(R.id.webView); webView.loadUrl("file:///android_asset/html/webpage_gif.html");

Heres es un ejemplo completo de estas dos opciones .


He tenido éxito con la solución propuesta en este artículo , una clase llamada GifMovieView , que presenta una View que luego se puede mostrar o agregar a un ViewGroup específico. Vea los otros métodos presentados en las partes 2 y 3 del artículo especificado.

El único inconveniente de este método es que el antialiasing en la película no es tan bueno (debe ser un efecto secundario de usar la Clase de Movie Android "sombreada"). A continuación, estará mejor configurando el fondo a un color sólido dentro de su GIF animado.


La manera fácil de mostrar GIF animados directamente desde la URL al diseño de su aplicación es usar la clase WebView.

Paso 1: En tu maquetación XML

<WebView android:id="@+id/webView" android:layout_width="50dp" android:layout_height="50dp" />

Paso 2: En tu actividad

WebView wb; wb = (WebView) findViewById(R.id.webView); wb.loadUrl("https://.......);

Paso 3: En tu Manifest.XML haz permiso de internet

<uses-permission android:name="android.permission.INTERNET" />

Paso 4: En caso de que quieras hacer que tu fondo GIF sea transparente y que GIF se ajuste a tu diseño

wb.setBackgroundColor(Color.TRANSPARENT); wb.getSettings().setLoadWithOverviewMode(true); wb.getSettings().setUseWideViewPort(true);


Manera más fácil - Se puede considerar el siguiente código

Podemos tomar ventaja de Imageview setImageResource, refiérase al siguiente código para obtener el mismo.

El siguiente código se puede usar para mostrar la imagen como GIF en caso de que tenga la imagen dividida múltiple de GIF. Simplemente divida el gif en png individual desde una herramienta en línea y ponga la imagen en el dibujo como en el siguiente orden

image_1.png, image_2.png, etc.

Tener el controlador para cambiar la imagen dinámicamente.

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


Me fue muy difícil tener un gif animado trabajando en Android. Solo tuve dos siguientes trabajando:

  1. WebView
  2. Ion

WebView funciona bien y es muy fácil, pero el problema es que hace que la vista se vuelva más lenta y que la aplicación no responda por un segundo. A mi no me gusto eso. Así que he intentado diferentes enfoques (NO TRABAJÓ):

  1. ImageViewEx está en desuso!
  2. picasso no cargó gif animado
  3. android-gif-drawable se ve muy bien, pero causó algunos problemas de NDK alámbricos en mi proyecto. Esto causó que mi biblioteca NDK local dejara de funcionar y no pude arreglarlo

Tuve algunos de ida y vuelta con Ion ; Finalmente, lo tengo funcionando, y es muy rápido :-)

Ion.with(imgView) .error(R.drawable.default_image) .animateGif(AnimateGifMode.ANIMATE) .load("file:///android_asset/animated.gif");


Nadie ha mencionado la biblioteca Ion o docs . funcionan muy bien

Es más fácil de manejar en comparación con un WebView.


Póngalo en una vista web, tiene que ser capaz de mostrarlo correctamente, ya que el navegador predeterminado admite archivos gif. (Froyo +, si no me equivoco)


Prueba esto, debajo del archivo de visualización de código gif en la barra de progreso

loading_activity.xml (en la carpeta Layout)

<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 (en la carpeta dibujable)

Aquí pongo black_gif.gif (en la carpeta dibujable), puedes poner tu propio gif aquí

<?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 (en la carpeta 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); } }



Resolví el problema dividiendo las animaciones GIF en marcos antes de guardarlo en el teléfono, por lo que no tendría que lidiar con él en Android.

Luego descargo todos los marcos en el teléfono, creo Drawable desde él y luego creo AnimationDrawable - muy similar al ejemplo de mi pregunta


Resolví esto dividiendo gif en marcos y usé animación estándar de Android


Similar a lo que dijo @Leonti, pero con un poco más de profundidad:

Lo que hice para resolver el mismo problema fue abrir GIMP, ocultar todas las capas excepto una, exportarla como su propia imagen y luego ocultar esa capa y mostrar la siguiente, etc., hasta que tuviera archivos de recursos individuales para cada una . Entonces podría usarlos como marcos en el archivo XML AnimationDrawable.


Solo quería agregar que la clase de Movie ahora está en desuso.

Esta clase fue desaprobada en el nivel de API P.

Se recomienda utilizar este

AnimatedImageDrawable

Dibujable para dibujar imágenes animadas (como GIF).


Use ImageViewEx , una biblioteca que hace que usar un gif sea tan fácil como usar un ImageView .



también poner (main / asset / htmls / name.gif) [con este html ajustar al tamaño]

<html style="margin: 0;"> <body style="margin: 0;"> <img src="name.gif" style="width: 100%; height: 100%" /> </body> </html>

declare en su Xml por ejemplo como este (main / res / layout / name.xml): [usted define el tamaño, por ejemplo]

<WebView android:layout_width="70dp" android:layout_height="70dp" android:id="@+id/webView" android:layout_gravity="center_horizontal" />

en su Actividad ponga el siguiente código dentro de onCreate

web = (WebView) findViewById(R.id.webView); web.setBackgroundColor(Color.TRANSPARENT); //for gif without background web.loadUrl("file:///android_asset/htmls/name.html");

Si quieres cargar dinámicamente tienes que cargar la vista web con datos:

// 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);

sugerencia: es mejor cargar gif con imágenes estáticas para obtener más información visite https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

Eso es todo, espero que ayudes.


Glide

Image Loader Library para Android, recomendado por Google.

  • Glide es bastante similar a Picasso pero esto es mucho más rápido que Picasso.
  • Glide consume menos memoria que Picasso.

Lo que Glide tiene pero Picasso no.

La capacidad de cargar animaciones GIF en un simple ImageView podría ser la característica más interesante de Glide. Y sí, no puedes hacer eso con Picasso. Algunos enlaces importantes-

  1. docs
  2. http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

Glide 4.6

1. cargar gif

GlideApp.with(context) .load(R.raw.gif) // or url .into(imageview);

2. Para obtener el objeto de archivo

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


ACTUALIZAR:

Utilice deslizamiento:

dependencies { compile ''com.github.bumptech.glide:glide:4.0.0'' }

uso:

Glide.with(context).load(GIF_URI).into(new GlideDrawableImageViewTarget(IMAGE_VIEW));

ver docs


Solo para la API de Android (Android Pie) 28 y +

utilizar AnimatedImageDrawable como

// 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()

Código XML, añadir un 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 es un hijo de Drawable y creado por ImageDecoder.decodeDrawable

ImageDecoder.decodeDrawable que requería la instancia de ImageDecoder.Source creada por ImageDecoder.createSource .

ImageDecoder.createSource solo puede tomar origen como nombre, ByteBuffer, File, resourceId, URI, ContentResolver para crear un objeto de origen y lo utiliza para crear AnimatedImageDrawable como Drawable (llamada polimórfica)

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)

Nota: También puede crear Bitmap usando ImageDecoder#decodeBitmap .

Salida:

AnimatedDrawable también admite cambio de tamaño, marco y manipulación de color


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