sonido programa partir para online hacer giphy fotos crear con como android animated-gif

android - programa - ¿Cómo encajar el contenido de la animación GIF en la vista y en el fondo de pantalla en vivo?



programa para crear gif (3)

OK creo que tengo como escalar el contenido. Sin embargo, no estoy seguro de por qué la aplicación aún falla al cambiar de orientación, y por qué la aplicación no muestra la vista previa de inmediato.

El proyecto está disponible here .

Para el centro interno, el código es:

canvas.scale((float)this.getWidth() / (float)movie.width(),(float)this.getHeight() / (float)movie.height());

Para el centro de cultivo, el código es:

canvas.scale(1.9f, 1.21f); //this changes according to screen size

para fit-center, puedo usar esto:

val canvasWidth = canvas.width.toFloat() val canvasHeight = canvas.height.toFloat() val bitmapWidth = curBitmap.width.toFloat() val bitmapHeight = curBitmap.height.toFloat() val scaleX = canvasWidth / bitmapWidth val scaleY = canvasHeight / bitmapHeight scale = if (scaleX * curBitmap.height > canvas.height) scaleY else scaleX x = (canvasWidth / 2f) - (bitmapWidth / 2f) * scale y = (canvasHeight / 2f) - (bitmapHeight / 2f) * scale ...

Fondo

Tengo una pequeña aplicación de fondo de pantalla en vivo, que quiero agregar soporte para que muestre animaciones GIF.

Para esto, he encontrado varias soluciones. Existe la solución de mostrar una animación GIF en una vista ( here ), e incluso hay una solución para mostrarla en un fondo de pantalla en vivo ( here ).

Sin embargo, para ambos, no encuentro cómo encajar bien el contenido de la animación GIF en el espacio que tiene, es decir, cualquiera de los siguientes:

  1. Cultivo central: se ajusta al 100% del contenedor (la pantalla en este caso), se recorta en los lados (arriba y abajo o izquierda y derecha) cuando sea necesario. No estira nada. Esto significa que el contenido parece estar bien, pero no se puede mostrar todo.
  2. ajuste centro - estirar para ajustar ancho / alto
  3. centrado interior: se establece como tamaño original, centrado y se estira para ajustarse al ancho / alto solo si es demasiado grande.

El problema

Ninguno de ellos es realmente sobre ImageView, así que no puedo usar el atributo scaleType.

Lo que he encontrado

Hay una solución que te da un GifDrawable ( here ), que puedes usar en ImageView, pero parece que es bastante lento en algunos casos, y no puedo averiguar cómo usarlo en LiveWallpaper y luego adaptarlo.

El código principal del manejo de GIF de LiveWallpaper es como tal ( here ):

class GIFWallpaperService : WallpaperService() { override fun onCreateEngine(): WallpaperService.Engine { val movie = Movie.decodeStream(resources.openRawResource(R.raw.cinemagraphs)) return GIFWallpaperEngine(movie) } private inner class GIFWallpaperEngine(private val movie: Movie) : WallpaperService.Engine() { private val frameDuration = 20 private var holder: SurfaceHolder? = null private var visible: Boolean = false private val handler: Handler = Handler() private val drawGIF = Runnable { draw() } private fun draw() { if (visible) { val canvas = holder!!.lockCanvas() canvas.save() movie.draw(canvas, 0f, 0f) canvas.restore() holder!!.unlockCanvasAndPost(canvas) movie.setTime((System.currentTimeMillis() % movie.duration()).toInt()) handler.removeCallbacks(drawGIF) handler.postDelayed(drawGIF, frameDuration.toLong()) } } override fun onVisibilityChanged(visible: Boolean) { this.visible = visible if (visible) handler.post(drawGIF) else handler.removeCallbacks(drawGIF) } override fun onDestroy() { super.onDestroy() handler.removeCallbacks(drawGIF) } override fun onCreate(surfaceHolder: SurfaceHolder) { super.onCreate(surfaceHolder) this.holder = surfaceHolder } } }

El código principal para manejar la animación GIF en una vista es como tal:

class CustomGifView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) { private var gifMovie: Movie? = null var movieWidth: Int = 0 var movieHeight: Int = 0 var movieDuration: Long = 0 var mMovieStart: Long = 0 init { isFocusable = true val gifInputStream = context.resources.openRawResource(R.raw.test) gifMovie = Movie.decodeStream(gifInputStream) movieWidth = gifMovie!!.width() movieHeight = gifMovie!!.height() movieDuration = gifMovie!!.duration().toLong() } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { setMeasuredDimension(movieWidth, movieHeight) } override fun onDraw(canvas: Canvas) { val now = android.os.SystemClock.uptimeMillis() if (mMovieStart == 0L) { // first time mMovieStart = now } if (gifMovie != null) { var dur = gifMovie!!.duration() if (dur == 0) { dur = 1000 } val relTime = ((now - mMovieStart) % dur).toInt() gifMovie!!.setTime(relTime) gifMovie!!.draw(canvas, 0f, 0f) invalidate() } } }

Las preguntas

  1. Dada una animación GIF, ¿cómo puedo escalarla en cada una de las formas anteriores?
  2. ¿Es posible tener una única solución para ambos casos?
  3. ¿Es posible usar la biblioteca GifDrawable (o cualquier otro dibujable para la materia) para el fondo de pantalla en vivo, en lugar de la clase Película? ¿Si es así, cómo?

EDITAR: después de encontrar la forma de escalar para 2 tipos, todavía necesito saber cómo escalar de acuerdo con el tercer tipo, y también quiero saber por qué sigue fallando después de los cambios de orientación y por qué no siempre muestra la vista previa de inmediato .

También me gustaría saber cuál es la mejor manera de mostrar la animación GIF aquí, porque actualmente solo actualizo el lienzo ~ 60 fps (1000/60 esperando entre cada 2 cuadros), sin tener en cuenta lo que hay en el archivo.

El proyecto está disponible here .


Si tiene Glide en su proyecto, puede cargar Gifs fácilmente, ya que proporciona GIF de dibujo a sus ImageViews y admite muchas opciones de escala (como el centro o un ancho determinado y ...).

Glide.with(context) .load(imageUrl or resourceId) .asGif() .fitCenter() //or other scaling options as you like .into(imageView);


Cambia el ancho y la altura de la película:

Agregue este código en el método onDraw antes de movie.draw

private fun draw() { if (!isVisible) return val canvas = holder!!.lockCanvas() ?: return canvas.save() //fit-center val scale = Math.min(canvas.width.toFloat() / movie.width().toFloat(), canvas.height.toFloat() / movie.height().toFloat()); val x = (canvas.width.toFloat() / 2f) - (movie.width().toFloat() / 2f) * scale; val y = (canvas.height.toFloat() / 2f) - (movie.height().toFloat() / 2f) * scale; canvas.translate(x, y) canvas.scale(scale, scale) movie.draw(canvas, 0f, 0f) canvas.restore() holder!!.unlockCanvasAndPost(canvas) movie.setTime((System.currentTimeMillis() % movie.duration()).toInt()) handler.removeCallbacks(drawGIF) handler.postDelayed(drawGIF, frameDuration.toLong()) }

o

private fun draw() { if (!isVisible) return val canvas = holder!!.lockCanvas() ?: return canvas.save() //center crop val scale = Math.max(canvas.width.toFloat() / movie.width().toFloat(), canvas.height.toFloat() / movie.height().toFloat()); val x = (canvas.width.toFloat() / 2f) - (movie.width().toFloat() / 2f) * scale; val y = (canvas.height.toFloat() / 2f) - (movie.height().toFloat() / 2f) * scale; canvas.translate(x, y) canvas.scale(scale, scale) movie.draw(canvas, 0f, 0f) canvas.restore() holder!!.unlockCanvasAndPost(canvas) movie.setTime((System.currentTimeMillis() % movie.duration()).toInt()) handler.removeCallbacks(drawGIF) handler.postDelayed(drawGIF, frameDuration.toLong()) }

Escala para rellenar y escalar para encajar

Ya hay una buena respuesta a eso:

https://.com/a/38898699/5675325