Comment afficher 2 vues, avec un effet gradient-fade sur Android?

Je souhaite avoir 2 vues affichées sur l'écran – l'un serait un aperçu de l'appareil photo, en haut, tandis que l'autre afficherait une image ou une carte google – et vivrait en bas de l'écran.

J'aimerais avoir une transition en forme de dégradé entre eux, alors il n'y a pas de frontière entre eux. Est-ce possible d'avoir un tel effet?

  • Truecaller android sdk Error Code 3
  • Lire la vidéo de youtube dans WebView
  • Création d'un nombre aléatoire à 4 chiffres et stockage dans une chaîne
  • Afficher l'émoticône personnalisée dans le clavier Android
  • Structure du projet Studio Android (vs Structure du projet Eclipse)
  • Découplage de la facturation dans l'application de l'activité
  • Edit: L'effet que j'aimerais atteindre devrait ressembler à ceci (la partie supérieure vient de l'aperçu de la caméra, alors que la partie inférieure devrait être une carte …):

    Mélange de carte en photo de caméra

    Sur l'iOS, j'ai eu un effet similaire avec CameraOverlay montrant la carte et configurant le masque de calque dans le dégradé:

    CAGradientLayer *gradient = [CAGradientLayer layer]; gradient.frame = self.map.bounds; gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite: 1.0 alpha: 0.0] CGColor], (id)[[UIColor colorWithWhite: 1.0 alpha: 1.0] CGColor], nil]; gradient.startPoint = CGPointMake(0.5f, 0.0f); gradient.endPoint = CGPointMake(0.5f, 0.5f); self.map.layer.mask = gradient; 

  • Impossible de vérifier / décocher CheckedTextView à l'intérieur de getView
  • Supprimer le titre de DatePickerDialog
  • Making Sense of Android méta-viewport mise à niveau: Qu'est-ce qui me manque?
  • Utilisation de styles de police par défaut dans Android
  • Android StrictMode InstanceCountViolation
  • LinearLayout superposé Support CoordinatorLayout
  • 2 Solutions collect form web for “Comment afficher 2 vues, avec un effet gradient-fade sur Android?”

    Cela est possible, mais peut-être un peu compliqué. Pour le simplifier, j'ai mis le code principal pour ce faire dans la réponse. Comme cela a été noté, vous avez besoin de deux vues pour le faire, un "sur le dessus" de l'autre. Le "plus bas" devrait être un SurfaceView, piloté par l'API de cartes. Le "plus haut" devrait montrer l'image de la caméra disparue sur elle.

    EDIT: Comme l'indique mr_archano, l'API est (maintenant) définie de telle sorte qu'aucune SurfaceView ne laisse passer les données de prévisualisation. Ho hum, telle est la nature du progrès, mais cela est également surmontable.

    Le code présente:

    • Le "SurfaceView" inférieur est piloté directement par le mécanisme d'aperçu de la caméra.
    • Le "surface" SurfaceView est pour l'API MAPS.
    • La vue "supérieure" est l'endroit où les données de la caméra sont rendues pour obtenir l'effet désiré.

    Le code central donne donc "aperçu de la caméra" sur "l'aperçu de la caméra", et l'image supérieure a été intentionnellement déformée, de sorte qu'il est clairement visible complètement en haut, s'effaçant au milieu et est allé en bas.

    Puis-je suggérer que la meilleure façon d'utiliser ce code est de mettre en œuvre ces quatre premières étapes par eux-mêmes et de le voir fonctionner, puis d'ajouter les deux dernières étapes et de voir ce travail avant d'insérer les concepts clés dans un autre, sans doute plus grand et plus Complexe, code.

    Premières quatre étapes:

    1. Créez une vue personnalisée pour l'affichage en haut, la caméra, la vue. Cette classe rend un bitmap sur tout ce qui se trouve en dessous. La valeur alpha dans chaque pixel dans le bitmap déterminera combien de la vue inférieure est permise.

       public class CameraOverlayView extends View { private Paint paint; private Size incomingSize; private Bitmap bitmap = null; public CameraOverlayView(Context context) { super(context); init(); } public CameraOverlayView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { paint = new Paint(); paint.setStyle(Style.FILL_AND_STROKE); paint.setColor(0xffffffff); paint.setTextSize((float) 20.0); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int width = canvas.getWidth(); int height = canvas.getHeight(); canvas.drawBitmap(bitmap, 0.0f, 0.0f, paint); } } 
    2. Mettez trois vues dans une image avec elles toutes définies pour fill_parent dans les deux sens. Le premier sera "en dessous" (SurfaceView afin que l'aperçu de l'appareil photo fonctionne). Le deuxième "au milieu" (la vue de surface pour Maps ou autre). Le troisième "en haut" (la vue pour l'image de la caméra disparue).

       <SurfaceView android:id="@+id/beneathSurfaceView" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <SurfaceView android:id="@+id/middleSurfaceView" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <com.blah.blah.blah.CameraOverlayView android:id="@+id/aboveCameraView" android:layout_width="fill_parent" android:layout_height="fill_parent" /> 

    3. Une activité principale dépouillée qui configurera la caméra et enverra l'image de prévisualisation automatique à la SurfaceView (inférieure) et aux données d'image d'aperçu à une routine de traitement. Il définit un rappel pour capturer les données de prévisualisation. Ces deux fonctionnent en parallèle.

       public class CameraOverlay extends Activity implements SurfaceHolder.Callback2 { private SurfaceView backSV; private CameraOverlayView cameraV; private SurfaceHolder cameraH; private Camera camera=null; private Camera.PreviewCallback cameraCPCB; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.camera_overlay); // Get the two views backSV = (SurfaceView) findViewById(R.id.beneathSurfaceView); cameraV = (CameraOverlayView) findViewById(R.id.aboveCameraView); // BACK: Putting the camera on the back SV (replace with whatever is driving that SV) cameraH = backSV.getHolder(); cameraH.addCallback(this); // FRONT: For getting the data from the camera (for the front view) cameraCPCB = new Camera.PreviewCallback () { @Override public void onPreviewFrame(byte[] data, Camera camera) { cameraV.acceptCameraData(data, camera); } }; } // Making the camera run and stop with state changes @Override public void onResume() { super.onResume(); camera = Camera.open(); camera.startPreview(); } @Override public void onPause() { super.onPause(); camera.setPreviewCallback(null); camera.stopPreview(); camera.release(); camera=null; } private void cameraImageToViewOn() { // FRONT cameraV.setIncomingSize(camera.getParameters().getPreviewSize()); camera.setPreviewCallback(cameraCPCB); } private void cameraImageToViewOff() { // FRONT camera.setPreviewCallback(null); } // The callbacks which mean that the Camera does stuff ... @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (holder == null) return; // stop preview before making changes try { cameraImageToViewOff(); // FRONT camera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or reformatting changes here // start preview with new settings try { camera.setPreviewDisplay(holder); //BACK camera.startPreview(); cameraImageToViewOn(); // FRONT } catch (Exception e){ } } @Override public void surfaceCreated(SurfaceHolder holder) { try { camera.setPreviewDisplay(holder); //BACK camera.startPreview(); cameraImageToViewOn(); // FRONT } catch (IOException e) { } } @Override public void surfaceDestroyed(SurfaceHolder holder) { } @Override public void surfaceRedrawNeeded(SurfaceHolder holder) { } } 

      Certaines choses manquent:

      • S'assurer que l'image de la caméra est la bonne orientation
      • S'assurer que l'image d'aperçu de la caméra est la taille optimale

    4. Maintenant, ajoutez deux fonctions à la vue créée à la première étape. Le premier assure que la vue connaît la taille des données d'image entrantes. Le second reçoit les données d'image d'aperçu, le transforme en un bitmap, le déformant en tant que visibilité et pour démontrer l'alpha fade.

       public void setIncomingSize(Size size) { incomingSize = size; if (bitmap != null) bitmap.recycle(); bitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888); } public void acceptCameraData(byte[] data, Camera camera) { int width = incomingSize.width; int height = incomingSize.height; // the bitmap we want to fill with the image int numPixels = width*height; // the buffer we fill up which we then fill the bitmap with IntBuffer intBuffer = IntBuffer.allocate(width*height); // If you're reusing a buffer, next line imperative to refill from the start, - if not good practice intBuffer.position(0); // Get each pixel, one at a time int Y; int xby2, yby2; int R, G, B, alpha; float U, V, Yf; for (int y = 0; y < height; y++) { // Set the transparency based on how far down the image we are: if (y<200) alpha = 255; // This image only at the top else if (y<455) alpha = 455-y; // Fade over the next 255 lines else alpha = 0; // nothing after that // For speed's sake, you should probably break out of this loop once alpha is zero ... for (int x = 0; x < width; x++) { // Get the Y value, stored in the first block of data // The logical "AND 0xff" is needed to deal with the signed issue Y = data[y*width + x] & 0xff; // Get U and V values, stored after Y values, one per 2x2 block // of pixels, interleaved. Prepare them as floats with correct range // ready for calculation later. xby2 = x/2; yby2 = y/2; U = (float)(data[numPixels + 2*xby2 + yby2*width] & 0xff) - 128.0f; V = (float)(data[numPixels + 2*xby2 + 1 + yby2*width] & 0xff) - 128.0f; // Do the YUV -> RGB conversion Yf = 1.164f*((float)Y) - 16.0f; R = (int)(Yf + 1.596f*V); G = 2*(int)(Yf - 0.813f*V - 0.391f*U); // Distorted to show effect B = (int)(Yf + 2.018f*U); // Clip rgb values to 0-255 R = R < 0 ? 0 : R > 255 ? 255 : R; G = G < 0 ? 0 : G > 255 ? 255 : G; B = B < 0 ? 0 : B > 255 ? 255 : B; // Put that pixel in the buffer intBuffer.put(Color.argb(alpha, R, G, B)); } } // Get buffer ready to be read intBuffer.flip(); // Push the pixel information from the buffer onto the bitmap. bitmap.copyPixelsFromBuffer(intBuffer); this.invalidate(); } 

      Notes sur la deuxième routine:

      • Il suppose le format de caméra entrant NV21. D'autres peuvent être disponibles, celui-ci est garanti pour y être, même s'il s'agit d'une douleur. Voir Conversion de YUV-> RVB (traitement d'image) -> YUV pendant onPreviewFrame dans Android? .
      • Cela pourrait probablement être fait plus rapidement, ou mieux, avec des versions plus récentes d'Android et une certaine optimisation de code.

    Ce code montre l'idée de base. Pour passer à la phase suivante:

    1. Réglez la vue de la surface de la caméra pour être suffisamment petite pour se cacher derrière la section non fanée de la vue supérieure. C'est-à-dire changer android:layout_height pour cela, disons, 60dp .

    2. Définissez le SurfaceView du milieu pour recevoir les informations de la carte.

    Malheureusement AFAIK, vous ne pouvez pas fusionner entre un aperçu de la caméra et une carte si les deux composants doivent être interactifs / en direct. Comme indiqué précédemment dans un commentaire précédent, cela est lié à la nature des deux widgets et aux limites de la composition de Android.

    L'aperçu de la caméra nécessite un SurfaceView afin de fonctionner correctement. Des documents officiels:

    SurfaceView frappe un trou dans sa fenêtre pour permettre à sa surface d'être affichée. La hiérarchie de la vue s'occupera de la composition correcte avec la Surface des frères et sœurs de la SurfaceView qui apparaîtraient normalement au-dessus. Cela peut être utilisé pour placer des superpositions telles que des boutons sur la surface, mais notons cependant qu'il peut avoir un impact sur les performances, car un composite alpha complet sera effectué chaque fois que la surface change.

    Google Maps v2 utilise SurfaceView aussi (regardez ici ), donc, essentiellement, vous avez deux instances de SurfaceView une sur l'autre et vous ne pouvez simplement pas appliquer un masque de dégradé pour obtenir ce que vous voulez, car vous n'avez aucun contrôle sur la façon dont chacun Le widget s'impose:

    • Prévisualisation de la caméra SurfaceView tampon de la caméra de réception et la rendez nativement
    • SurfaceView est rendu dans un autre processus.

    En outre, l'utilisation de deux exemples de SurfaceView ensemble est fortement déconseillée comme indiqué ici :

    La façon dont la vue de surface est implémentée est qu'une surface distincte est créée et commandée en Z derrière sa fenêtre contenant, et des pixels transparents sont dessinés dans le rectangle où SurfaceView permet de voir la surface derrière. Nous n'avons jamais eu l'intention de permettre de multiples vues de surface.

    Je pense que la seule option que vous avez est de ne choisir qu'un seul pour être en direct / interactif et dessiner l'autre comme un gradient d'image statique sur le dessus.

    MODIFIER

    Afin de valider davantage mes déclarations précédentes, ci-dessous un devis de documents officiels sur l'utilisation de la caméra :

    Important: Passez un SurfaceHolder entièrement initialisé pour configurerPreviewDisplay (SurfaceHolder). Sans surface, la caméra ne pourra pas démarrer l'aperçu .

    Donc, vous êtes obligé d'utiliser un SurfaceView afin d'obtenir l'aperçu de Camera . Toujours.
    Et juste pour me répéter: vous n'avez aucun contrôle sur la façon dont ces pixels sont rendus, car Camera écrit directement le framebuffer à l'aide de l'Aperçu SurfaceHolder .

    En conclusion, vous avez deux instances SurfaceView entièrement opaques et vous ne pouvez SurfaceView pas appliquer de rendu de fantaisie à leur contenu, donc je pense que cet effet n'est tout simplement pas pratique dans Android.

    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.