web-dev-qa-db-fra.com

Android - Comment positionner la vue hors écran?

J'essaie d'animer une ImageView simple dans mon application et je veux qu'elle glisse depuis le bas de l'écran et arrive à une position de repos où les 50 pixels supérieurs de la vue se trouvent hors du haut de l'écran (par exemple la position finale de l'ImageView doit être de -50 px en X). J'ai essayé d'utiliser AbsoluteLayout pour ce faire, mais cela coupe en fait les 50 pixels supérieurs de l'ImageView de telle sorte que les 50 pixels supérieurs ne sont jamais rendus. J'ai besoin que les 50px supérieurs de l'ImageView soient visibles/rendus pendant son animation, puis s'arrêtent légèrement hors écran. J'espère que je l'ai assez bien expliqué.

Voici ce que j'utilise actuellement en tant que mise en page et animation de diaporama (cela ne rend pas actuellement les 50 premiers pixels de l'ImageView):

Disposition:

<?xml version="1.0" encoding="utf-8"?>
   <AbsoluteLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
      Android:layout_height="fill_parent" 
      Android:layout_width="fill_parent" 
      Android:id="@+id/QuickPlayClipLayout">
      <ImageView Android:id="@+id/Clip"
         Android:background="@drawable/clip" 
         Android:layout_width="fill_parent" 
         Android:layout_height="wrap_content" 
         Android:layout_y="-50dp">
      </ImageView>
   </AbsoluteLayout>

Animation:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android">
   <translate Android:fromYDelta="100%p" 
       Android:toYDelta="0"
       Android:duration="1000"/>
   <alpha Android:fromAlpha="0.0" 
       Android:toAlpha="1.0"
       Android:duration="1000" />
</set>

Merci d'avance.

59
RyanM

J'ai trouvé une solution à cela qui devrait être facile à mettre en œuvre. Il s'agit de modifier la mise en page et l'activité de gonfler la mise en page ... voir ci-dessous:

Activité (QuickPlay.Java):

public class QuickPlay extends Activity implements AnimationListener
{
    private ImageView myImageView;
    private LinearLayout LL;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.quick_play_screen);

        myImageView = (ImageView) this.findViewById(R.id.Clip);
        LL = (LinearLayout) this.findViewById(R.id.QuickPlayClipLayout);

        //finally
        Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_in_quickplay);
        anim.setAnimationListener(this);
        LL.startAnimation(anim);
    }
    @Override
    public void onAnimationEnd(Animation animation){}

    @Override
    public void onAnimationRepeat(Animation animation){}

    @Override
    public void onAnimationStart(Animation animation)
    {
        // This is the key...
        //set the coordinates for the bounds (left, top, right, bottom) based on the offset value (50px) in a resource XML
        LL.layout(0, -(int)this.getResources().getDimension(R.dimen.quickplay_offset), 
                LL.getWidth(), LL.getHeight() + (int)this.getResources().getDimension(R.dimen.quickplay_offset));
    }
}

Nouveau LinearLayout (CustomLinearLayout.Java):

public class CustomLinearLayout extends LinearLayout
{
    private Context myContext;

    public CustomLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        myContext = context;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec+((int)myContext.getResources().getDimension(R.dimen.quickplay_offset)));
    }
}

Disposition (/res/layout/quick_play_screen.xml):

<?xml version="1.0" encoding="utf-8"?>
   <com.games.mygame.CustomLinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
      Android:layout_height="fill_parent" 
      Android:layout_width="fill_parent" 
      Android:id="@+id/QuickPlayClipLayout">
      <ImageView Android:id="@+id/Clip"
         Android:background="@drawable/clip" 
         Android:layout_width="fill_parent" 
         Android:layout_height="wrap_content">
      </ImageView>
   </com.games.mygame.CustomLinearLayout>

Ressource (/res/values/constants.xml):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="quickplay_offset">50dp</dimen>
</resources>

Animation (/res/anim/slide_in_quickplay.xml):

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:Android="http://schemas.Android.com/apk/res/Android">
   <translate Android:fromYDelta="100%p" 
       Android:toYDelta="0"
       Android:duration="1000"/>
   <alpha Android:fromAlpha="0.0" 
       Android:toAlpha="1.0"
       Android:duration="1000" />
</set>

Le programme fait maintenant exactement ce dont j'ai besoin. L'ensemble de la mise en page commence en bas de l'écran, glisse en 1 seconde et s'arrête où le haut de la mise en page est en fait à 50 pixels en haut de l'écran (c'est-à-dire LL.getTop() = -50) et le bas de la la mise en page se trouve en bas de l'écran (c'est-à-dire LL.getBottom() = 530 = 480 + 50).

33
RyanM

Au lieu de cela, nous pouvons simplement donner des valeurs négatives à layout_margin (haut/gauche/droite/bas), par exemple: si vous souhaitez que votre vue soit désactivée du haut de l'écran, vous pouvez spécifier

Android:layout_marginTop="-40dp"
31
arun

Pour positionner ma vue hors écran, j'ai utilisé le code suivant:

View myView = /* view you want to position offscreen */
int amountOffscreen = (int)(myView.getWidth() * 0.8); /* or whatever */
boolean offscreen = /* true or false */


int xOffset = (offscreen) ? amountOffscreen : 0;
RelativeLayout.LayoutParams rlParams = 
    (RelativeLayout.LayoutParams)myView.getLayoutParams();
rlParams.setMargins(-1*xOffset, 0, xOffset, 0);
myView.setLayoutParams(rlParams);

Ce code positionnera myView hors écran par amountOffscreen, ce qui dans ce cas met 80% de la vue hors écran, ne laissant que 20% à l'écran.

N'utilisez pas directement la méthode layout () - Android effectuera des appels ultérieurs pour invalider votre vue pour des raisons aléatoires et seuls les layoutParams sont conservés lors des appels invalidés. Si vous êtes curieux, consultez les lignes 904 à 912 de ce fichier pour voir pourquoi vous devez modifier le layoutParams.

30
esilver

C'est facile à faire si vous passez à l'utilisation d'un Canvas; ceux-ci prennent en charge le retrait de l'écran sans aucun problème. Cependant, ce sera plus compliqué à mettre en œuvre. Vous devez implémenter un View personnalisé et écrire votre propre animation dans le code. Cela se résume essentiellement à une gestion graphique 2D simple plutôt qu'à des vues utilisant des animations XML intégrées. Il peut y avoir un moyen de le faire avec XML, mais je connais beaucoup mieux les toiles. Un très bon endroit pour voir comment cela est géré dans le code est l'exemple de jeu Lunar Lander fourni avec le SDK.

En gros, les étapes que vous devrez suivre sont les suivantes:

  1. Mettez une vue personnalisée dans le fichier XML, en utilisant quelque chose comme <your.package.AnimatingView>, En définissant sa taille sur fill-parent.

  2. Définissez ensuite une classe AnimatingView, qui extends SurfaceView and implements SurfaceHolder.Callback. (Cela vous donne accès au dessin Canvas immédiatement plutôt qu'en utilisant la méthode invalidate(). Ceci est important car invalidate () ne s'actualise que lorsque le thread est inactif, par exemple à la fin de la Pour implémenter votre animation, vous devez la faire dessiner immédiatement.)

  3. Vous pouvez ensuite implémenter une boucle qui dessine votre image animée sur l'écran. La boucle doit commencer par dessiner tout l'arrière-plan (car la toile n'est pas automatiquement effacée), puis dessiner l'image à sa nouvelle position en fonction du temps écoulé. Par exemple, si vous voulez que votre animation prenne 1 seconde, alors vous savez que si 200 ms se sont écoulées, la vue ne devrait avoir déplacé que 200/1000, ou 1/5, du chemin de sa position de départ à la position finale .

Vous pouvez voir quelques exemples de ce que je veux dire dans mes autres réponses aux questions d'animation: réponse de base sur le tilité d'utiliser SurfaceView et et exemple de la boucle à utiliser . Remarque: la deuxième question concernait la rotation, et donc certaines des difficultés dont j'ai parlé ne vous concerneront pas. Bonne chance!

9
Steve Haley

Avec Android:translationX et Android:translationY

<RelativeLayout
        Android:translationX="-600dp"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent">
3
Pablo Cegarra

J'avais un groupe de vues avec des enfants et je faisais glisser la vue vers l'écran depuis le bas - un peu comme un tiroir. Je lâchais alors et si la marge supérieure du groupe de vues était dans la moitié supérieure de l'écran, je l'animerais vers le haut après que l'utilisateur a relâché le toucher.

Lorsque cela se produisait, les images dans les enfants du groupe de visualisation étaient recadrées pendant l'animation mais étaient ensuite affichées après l'animation.

Le problème: la hauteur de viewgroup était wrap_content. J'ai résolu ce problème en définissant la hauteur sur une valeur qui s'étirait sur l'écran avant le début de l'animation.

2
Chris Sprague