Contexte
Je suis en train de créer un fond d'écran qui peut afficher une vidéo. Au début, je pensais que cela allait être très difficile, alors certaines personnes m'ont suggéré d'utiliser des solutions OpenGL ou d'autres solutions très complexes (telles que celui-ci ).
Quoi qu'il en soit, pour cela, j'ai trouvé divers endroits qui en parlent, et en me basant sur ceci bibliothèque github (qui a quelques bugs), j'ai finalement réussi à le faire fonctionner.
Le problème
J'ai réussi à afficher une vidéo, mais je ne trouve pas le moyen de contrôler la façon dont elle est affichée par rapport à la résolution de l'écran.
Actuellement, il est toujours étiré à la taille de l'écran, ce qui signifie que ceci (vidéo prise de ici ) :
doit être montré comme ça :
La raison en est le rapport d'aspect différent : 560x320 (résolution vidéo) contre 1080x1920 (résolution du dispositif).
Note : Je suis bien conscient des solutions de vidéos de mise à l'échelle, qui sont disponibles sur divers dépôts Github (tels que ici ), mais je m'intéresse à un fond d'écran. En tant que tel, il n'a pas de vue, donc il est plus limité sur la façon de faire les choses. Pour être plus précis, une solution ne peut avoir aucun type de layout, un TextureView ou un SurfaceView, ou tout autre type de View.
Ce que j'ai essayé
J'ai essayé de jouer avec divers champs et fonctions du SurfaceHolder, mais sans succès jusqu'à présent. Exemples :
-
setVideoScalingMode - soit il se plante, soit il ne fait rien.
-
en changeant [surfaceFrame](https://developer.android.com/reference/android/view/SurfaceHolder.html#getSurfaceFrame()) - même.
Voici le code actuel que j'ai réalisé (projet complet disponible) ici ) :
class MovieLiveWallpaperService : WallpaperService() {
override fun onCreateEngine(): WallpaperService.Engine {
return VideoLiveWallpaperEngine()
}
private enum class PlayerState {
NONE, PREPARING, READY, PLAYING
}
inner class VideoLiveWallpaperEngine : WallpaperService.Engine() {
private var mp: MediaPlayer? = null
private var playerState: PlayerState = PlayerState.NONE
override fun onSurfaceCreated(holder: SurfaceHolder) {
super.onSurfaceCreated(holder)
Log.d("AppLog", "onSurfaceCreated")
mp = MediaPlayer()
val mySurfaceHolder = MySurfaceHolder(holder)
mp!!.setDisplay(mySurfaceHolder)
mp!!.isLooping = true
mp!!.setVolume(0.0f, 0.0f)
mp!!.setOnPreparedListener { mp ->
playerState = PlayerState.READY
setPlay(true)
}
try {
//mp!!.setDataSource(this@MovieLiveWallpaperService, Uri.parse("http://techslides.com/demos/sample-videos/small.mp4"))
mp!!.setDataSource(this@MovieLiveWallpaperService, Uri.parse("android.resource://" + packageName + "/" + R.raw.small))
} catch (e: Exception) {
}
}
override fun onDestroy() {
super.onDestroy()
Log.d("AppLog", "onDestroy")
if (mp == null)
return
mp!!.stop()
mp!!.release()
playerState = PlayerState.NONE
}
private fun setPlay(play: Boolean) {
if (mp == null)
return
if (play == mp!!.isPlaying)
return
when {
!play -> {
mp!!.pause()
playerState = PlayerState.READY
}
mp!!.isPlaying -> return
playerState == PlayerState.READY -> {
Log.d("AppLog", "ready, so starting to play")
mp!!.start()
playerState = PlayerState.PLAYING
}
playerState == PlayerState.NONE -> {
Log.d("AppLog", "not ready, so preparing")
mp!!.prepareAsync()
playerState = PlayerState.PREPARING
}
}
}
override fun onVisibilityChanged(visible: Boolean) {
super.onVisibilityChanged(visible)
Log.d("AppLog", "onVisibilityChanged:" + visible + " " + playerState)
if (mp == null)
return
setPlay(visible)
}
}
class MySurfaceHolder(private val surfaceHolder: SurfaceHolder) : SurfaceHolder {
override fun addCallback(callback: SurfaceHolder.Callback) = surfaceHolder.addCallback(callback)
override fun getSurface() = surfaceHolder.surface!!
override fun getSurfaceFrame() = surfaceHolder.surfaceFrame
override fun isCreating(): Boolean = surfaceHolder.isCreating
override fun lockCanvas(): Canvas = surfaceHolder.lockCanvas()
override fun lockCanvas(dirty: Rect): Canvas = surfaceHolder.lockCanvas(dirty)
override fun removeCallback(callback: SurfaceHolder.Callback) = surfaceHolder.removeCallback(callback)
override fun setFixedSize(width: Int, height: Int) = surfaceHolder.setFixedSize(width, height)
override fun setFormat(format: Int) = surfaceHolder.setFormat(format)
override fun setKeepScreenOn(screenOn: Boolean) {}
override fun setSizeFromLayout() = surfaceHolder.setSizeFromLayout()
override fun setType(type: Int) = surfaceHolder.setType(type)
override fun unlockCanvasAndPost(canvas: Canvas) = surfaceHolder.unlockCanvasAndPost(canvas)
}
}
Les questions
J'aimerais savoir comment ajuster l'échelle du contenu en fonction de ce que nous avons pour ImageView, tout en conservant le rapport d'aspect :
- center-crop - s'adapte à 100% du conteneur (l'écran dans ce cas), en recadrant sur les côtés (haut et bas ou gauche et droite) si nécessaire. Il n'y a pas d'étirement. Cela signifie que le contenu semble correct, mais qu'il ne sera peut-être pas entièrement affiché.
- fit-center - s'étirer pour s'adapter à la largeur/hauteur
- center-inside - défini comme la taille originale, centré, et étiré pour s'adapter à la largeur/hauteur uniquement s'il est trop grand.
0 votes
Avez-vous essayé de définir la taille de la vidéo sur le support de surface en utilisant setFixedSize ?
0 votes
@SuhaibRoomy Pour une raison quelconque, ça me donne
UnsupportedOperationException: Wallpapers currently only support sizing from layout
. De plus, je ne sais pas avec quelles valeurs le régler.0 votes
Vous avez une vidéo, donc à moins que vous ne modifiiez le fichier lui-même, vous devez la configurer pour qu'elle soit lue dans une mise en page dimensionnée. Je ne pense pas que ce soit possible avec le WallpaperService. Avez-vous essayé Daydream ?
0 votes
@ChVas Je parle du fond d'écran en direct. Pas de Daydream. De plus, c'est possible. J'ai vu d'autres fonds d'écran le faire.
0 votes
@androiddeveloper avez-vous essayé este
0 votes
@Nainal Comment puis-je l'essayer ? Toutes les réponses concernent les vues et l'utilisation de LayoutParams. La seule solution sans cela - est d'utiliser
setFixedSize
que j'ai écrit et qui provoque un crash.0 votes
Pourriez-vous fournir un lien vers github (ou autre) pour le projet ? Le lien que vous avez fourni n'est plus disponible.
0 votes
@Jalvap OK lien mis à jour.
0 votes
C'est probablement une très mauvaise idée, mais la seule qui me vient à l'esprit et qui pourrait fonctionner est de créer un canevas, d'extraire l'image par image du film et de la dessiner sur le canevas, mais cela sera extrêmement coûteux. Vous pourrez alors manipuler l'image comme bon vous semble.
0 votes
Je veux une solution efficace. Elle doit être fluide.
0 votes
Avez-vous un
xml
pour cela ?0 votes
@AAShakil Fichier XML pour quoi faire ? C'est un fond d'écran vivant. Tout en code.
0 votes
Quelle est la version minimale de l'API sur laquelle vous aimeriez travailler ? Le retour en arrière pour les fonds d'écran en direct ?
0 votes
@TheHebrewHammer Relativement élevé actuellement (minSdkVersion 27) , mais pourrait être plus faible à l'avenir. Pourquoi ?
0 votes
Pas encore de raison, je voulais juste avoir toutes les informations pertinentes avant de commencer lundi. J'ai fait un tas de travaux sur l'AR avec opengl, mais je n'ai jamais touché aux fonds d'écran en direct, ça devrait être amusant.
0 votes
@TheHebrewHammer OK, merci.
0 votes
J'ai obtenu
center-crop
yfit-center
jusqu'à présent... Je travaille encore surcenter-inside
0 votes
@TheHebrewHammer Wow. Merci.
1 votes
Ok, quelques heures plus tard, et ce que j'ai obtenu est une explication détaillée de la difficulté de faire fit-top, fit-center, ou fit-bottom. Je vais toujours essayer plus tard, mais je pense que pour l'instant, vous êtes coincé avec fit-xy et center-crop. Je vais poster ce que j'ai jusqu'à présent demain et je mettrai à jour si je trouve un moyen raisonnable d'obtenir l'autre mode.
0 votes
MediPlayer
a sa propre méthode pour définir la mise à l'échelle. Avez-vous essayé avecVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
?0 votes
@Ircover J'ai déjà écrit sur cette méthode sur la question elle-même. Veuillez relire ce que j'ai écrit. Peut-être que je ne l'utilise pas correctement, car elle se bloque ou ne fait rien. Avez-vous réussi à
0 votes
@TheHebrewHammer Pouvez-vous s'il vous plaît afficher la solution que vous avez faite jusqu'à présent ? Celle avec les deux échelles ? Je pense que le center-crop est meilleur que le fit-xy que j'ai trouvé...
0 votes
C'est celui que j'ai posté, il y a un lien GitHub pour la source complète.
0 votes
@TheHebrewHammer Pour une raison quelconque, chaque fois que j'essaie de cloner, il n'a pas les fichiers qui sont sur le site Web. Il affiche quelque chose avec RecyclerView. C'est bizarre. J'ai dû télécharger le fichier zip à la place. Je le vérifierai plus tard. Je dois y aller maintenant. S'il vous plaît, écrivons sur la réponse que vous avez écrite plutôt qu'ici, ok ?
0 votes
Assurez-vous d'aller dans la bonne branche
0 votes
@TheHebrewHammer Oh vous avez déjà créé plusieurs branches... Mais l'autre semble bizarre. Il a RecyclerView... En outre, le projet, pour une raison quelconque, ne me laisse pas avoir l'auto-complétion sur l'IDE. Il ne marque même pas les erreurs. Et lorsque j'essaye de centrer la culture, pour une raison quelconque, elle ne s'affiche pas bien sur l'écran de prévisualisation (avant de la définir), en utilisant l'intention ACTION_CHANGE_LIVE_WALLPAPER, mais elle semble fonctionner lorsque je la définis.
0 votes
Ouais, donc je vais commencer à utiliser un seul dépôt pour tous mes échantillons de stack overflow. Je dois nettoyer le master pour que ce soit un projet vierge, les branches sont les ID des questions de stack overflow. Internet ici est très aléatoire mais pour l'instant je n'ai pas supporté de configuration dynamique, vous devez le compiler avec CENTER_CROP comme mode.
0 votes
@TheHebrewHammer Je sais. C'est ce que j'ai fait. Dans la prévisualisation, ça n'a pas l'air bien, mais quand on l'installe vraiment, ça fonctionne bien.
0 votes
C'est très étrange, j'ai utilisé un pixel et un Nexus 6 et la prévisualisation et le jeu final semblaient bons. Quel appareil et quel niveau d'API utilisez-vous ? J'aimerais bien essayer de reproduire ce phénomène.
0 votes
@TheHebrewHammer J'ai un Pixel 2 avec Android P. Voici le projet modifié et les images de ce que je vois (l'IDE l'affiche différemment pour une raison quelconque) du problème : issuetracker.google.com/issues/116250247
0 votes
Ok, ma femme a un pixel 2 donc je testerai à mon retour de vacances sur celui-là. Je fais tourner P sur mon pixel, c'est bizarre que ce soit différent.
0 votes
S'il vous plaît, continuons cela sur la réponse que vous avez écrite et non ici. Par ailleurs, avez-vous compris ce que j'ai essayé de montrer ? L'étape de prévisualisation est différente de celle du lanceur (après le réglage du fond d'écran). Pour moi, cela ressemble à un bug (ceci et le fait que l'IDE a une façon différente d'afficher le contenu que ce qui est sur l'appareil).