Android - comment créer une transition d'un élément dans listview à une activité complète?

ce que je veux, c'est que lorsque l'utilisateur clique sur un élément de liste dans un ListView, il convertisse à une activité entière (comme vous pouvez le voir dans l'exemple suivant), mais je n'ai pas pu trouver de tutoriel expliquant cela et, en fait, je ne sais pas comment ce mouvement est appelé.

En d'autres termes, ce que je veux réaliser est:

  1. Augmentation de l'Élément de Liste d'élévation quand on clique dessus (comme vous pouvez le voir dans le droit gif)

  2. étendre et transformer l'élément de la liste à la disposition suivante des fragments/activités qui contient des informations détaillées sur l'élément cliqué

enter image description here

j'ai essayé beaucoup de transitions, mais sans succès. Quelqu'un peut-il m'aider à accomplir cette mission?

23
demandé sur Antonio 2015-10-28 18:19:20

4 réponses

je construis une petite application d'échantillon que les transitions entre deux activités avec l'effet désiré: Sample Application

toutefois, les transitions dans les GIF fournis sont légèrement différentes. Le la transition dans le gif à gauche fait passer l'élément list dans la zone de contenu de la deuxième activité (la barre d'outils reste en place). Dans le gif à droite, la transition transforme l'élément list en écran complet de la deuxième activité. Le code suivant fournit l'effet dans le gif de gauche. Toutefois, il devrait être possible d'adapter la solution avec des modifications mineures pour réaliser la transition dans le bon gif.

notez que cela ne fonctionne que sur Lollipop. Cependant, il est possible de simuler un effet différent sur des appareils plus anciens. De plus, le seul but du code fourni est de montrer comment il pourrait être fait. Ne l'utilisez pas directement dans votre application.

Activité principale:

public class MainActivity extends AppCompatActivity {

    MyAdapter myAdapter;

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

        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
        ListView listView = (ListView) findViewById(R.id.list_view);

        myAdapter = new MyAdapter(this, 0, DataSet.get());

        listView.setAdapter(myAdapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) {
                startTransition(view, myAdapter.getItem(position));
            }
        });
    }

    private void startTransition(View view, Element element) {
        Intent i = new Intent(MainActivity.this, DetailActivity.class);
        i.putExtra("ITEM_ID", element.getId());

        Pair<View, String>[] transitionPairs = new Pair[4];
        transitionPairs[0] = Pair.create(findViewById(R.id.toolbar), "toolbar"); // Transition the Toolbar
        transitionPairs[1] = Pair.create(view, "content_area"); // Transition the content_area (This will be the content area on the detail screen)

        // We also want to transition the status and navigation bar barckground. Otherwise they will flicker
        transitionPairs[2] = Pair.create(findViewById(android.R.id.statusBarBackground), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME);
        transitionPairs[3] = Pair.create(findViewById(android.R.id.navigationBarBackground), Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME);
        Bundle b = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, transitionPairs).toBundle();

        ActivityCompat.startActivity(MainActivity.this, i, b);
    }
}

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        android:transitionName="toolbar" />

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

activité détaillée:

public class DetailActivity extends AppCompatActivity {

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

        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));

        long elementId = getIntent().getLongExtra("ITEM_ID", -1);
        Element element = DataSet.find(elementId);


        ((TextView) findViewById(R.id.title)).setText(element.getTitle());
        ((TextView) findViewById(R.id.description)).setText(element.getDescription());

        // if we transition the status and navigation bar we have to wait till everything is available
        TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar(this);
        // set a custom shared element enter transition
        TransitionHelper.setSharedElementEnterTransition(this, R.transition.detail_activity_shared_element_enter_transition);
    }
}

activity_detail.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        android:transitionName="toolbar" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#abc"
        android:orientation="vertical"
        android:paddingBottom="200dp"
        android:transitionName="content_area"
        android:elevation="10dp">

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/description"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

detail_activity_shared_element_enter_transition.xml (/res / transition/):

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="together">
    <changeBounds/>
    <changeTransform/>
    <changeClipBounds/>
    <changeImageTransform/>
    <transition class="my.application.transitions.ElevationTransition"/>
</transitionSet>

mon.application.transition.Elevationtransion:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class ElevationTransition extends Transition {

    private static final String PROPNAME_ELEVATION = "my.elevation:transition:elevation";

    public ElevationTransition() {
    }

    public ElevationTransition(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        captureValues(transitionValues);
    }

    @Override
    public void captureEndValues(TransitionValues transitionValues) {
        captureValues(transitionValues);
    }

    private void captureValues(TransitionValues transitionValues) {
        Float elevation = transitionValues.view.getElevation();
        transitionValues.values.put(PROPNAME_ELEVATION, elevation);
    }

    @Override
    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
        if (startValues == null || endValues == null) {
            return null;
        }

        Float startVal = (Float) startValues.values.get(PROPNAME_ELEVATION);
        Float endVal = (Float) endValues.values.get(PROPNAME_ELEVATION);
        if (startVal == null || endVal == null || startVal.floatValue() == endVal.floatValue()) {
            return null;
        }

        final View view = endValues.view;
        ValueAnimator a = ValueAnimator.ofFloat(startVal, endVal);
        a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                view.setElevation((float)animation.getAnimatedValue());
            }
        });

        return a;
    }
}

TransitionHelper:

public class TransitionHelper {

    public static void fixSharedElementTransitionForStatusAndNavigationBar(final Activity activity) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
            return;

        final View decor = activity.getWindow().getDecorView();
        if (decor == null)
            return;
        activity.postponeEnterTransition();
        decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @TargetApi(Build.VERSION_CODES.LOLLIPOP)
            @Override
            public boolean onPreDraw() {
                decor.getViewTreeObserver().removeOnPreDrawListener(this);
                activity.startPostponedEnterTransition();
                return true;
            }
        });
    }

    public static void setSharedElementEnterTransition(final Activity activity, int transition) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
            return;
        activity.getWindow().setSharedElementEnterTransition(TransitionInflater.from(activity).inflateTransition(transition));
    }
}

Alors, quelles sont les différentes parties ici: Nous avons deux activités. Au cours de la transition, quatre points de vue sont échangés entre les activités.

  • barre d'outils: comme dans la gauche gif la barre d'outils ne bouge pas avec le reste du contenu.

  • ListView de Vue de l'élément -> devient l'affichage du contenu de la DetailActivity

  • StatusBar et NavigationBar arrière-plan: si nous n'ajoutons pas ces vues à l'ensemble des vues transitionnées, elles disparaîtront et reviendront pendant la transition. Cela nécessite toutefois de retarder la transition enter (voir: TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar )

Dans le MainActivity la transition vues sont ajoutés à l'offre groupée qui est utilisé pour démarrer le DetailActivity . En outre, les vues transitionnées doivent être nommées ( transitionName ) dans les deux activités. Cela peut être fait dans la mise en page xml aussi bien que de façon programmatique.

l'ensemble par défaut des transitions, qui est utilisé pendant la transition d'éléments partagés, affecte différents aspects de la vue(par exemple: les limites de la vue - voir 2 ). Cependant, les différences dans l'élévation de vue ne sont pas animées. C'est pourquoi la solution présentée utilise la personnalisation ElevationTransition.

17
répondu Andreas Wenger 2015-11-06 01:14:25

essayez ceci.. Matériel-Animations

blueIconImageView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent i = new Intent(MainActivity.this, SharedElementActivity.class);

        View sharedView = blueIconImageView;
        String transitionName = getString(R.string.blue_name);

        ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
        startActivity(i, transitionActivityOptions.toBundle());
    }
});

SharedElements

3
répondu Carlos.V 2015-10-28 17:17:19

L'Animation dont vous avez besoin est appelée Transition D'activité entre des éléments partagés. Par la recherche j'ai trouvé que vous devriez:

  1. Placez votre vue de ListView dans un format relatif
  2. OnClick, gonfler une copie de votre moteur de rendu
  3. trouver les coordonnées globales de l'emplacement du renderer relation avec le parent du ListView
  4. ajouter le renderer copié au RelativeLayout (parent de ListView)
  5. Animer la listView loin
  6. Sur la fin de l'animer, animer votre nouveau moteur de rendu
  7. Profit!

     public class MainActivity extends Activity {
    
     private RelativeLayout layout;
            private ListView listView;
            private MyRenderer selectedRenderer;
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                layout = new RelativeLayout(this);
                setContentView(layout);
                listView = new ListView(this);
                RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
                        RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
                layout.addView(listView, rlp);
    
                listView.setAdapter(new MyAdapter());
                listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    
                        // find out where the clicked view sits in relationship to the
                        // parent container
                        int t = view.getTop() + listView.getTop();
                        int l = view.getLeft() + listView.getLeft();
    
                        // create a copy of the listview and add it to the parent
                        // container
                        // at the same location it was in the listview
                        selectedRenderer = new MyRenderer(view.getContext());
                        RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(view.getWidth(), view
                                .getHeight());
                        rlp.topMargin = t;
                        rlp.leftMargin = l;
                        selectedRenderer.textView.setText(((MyRenderer) view).textView.getText());
                        layout.addView(selectedRenderer, rlp);
                        view.setVisibility(View.INVISIBLE);
    
                        // animate out the listView
                        Animation outAni = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f,
                                Animation.RELATIVE_TO_SELF, -1f, Animation.RELATIVE_TO_SELF, 0f,
                                Animation.RELATIVE_TO_SELF, 0f);
                        outAni.setDuration(1000);
                        outAni.setFillAfter(true);
                        outAni.setAnimationListener(new Animation.AnimationListener() {
                            @Override
                            public void onAnimationStart(Animation animation) {
                            }
    
                            @Override
                            public void onAnimationRepeat(Animation animation) {
                            }
    
                            @Override
                            public void onAnimationEnd(Animation animation) {
                                ScaleAnimation scaleAni = new ScaleAnimation(1f, 
                                        1f, 1f, 2f, 
                                        Animation.RELATIVE_TO_SELF, 0.5f,
                                        Animation.RELATIVE_TO_SELF, 0.5f);
                                scaleAni.setDuration(400);
                                scaleAni.setFillAfter(true);
                                selectedRenderer.startAnimation(scaleAni);
                            }
                        });
    
                        listView.startAnimation(outAni);
                    }
                });
            }
    
            public class MyAdapter extends BaseAdapter {
                @Override
                public int getCount() {
                    return 10;
                }
    
                @Override
                public String getItem(int position) {
                    return "Hello World " + position;
                }
    
                @Override
                public long getItemId(int position) {
                    return position;
                }
    
                @Override
                public View getView(int position, View convertView, ViewGroup parent) {
                    MyRenderer renderer;
                    if (convertView != null)
                        renderer = (MyRenderer) convertView;
                    else
                        renderer = new MyRenderer(MainActivity.this);
                    renderer.textView.setText(getItem(position));
                    return renderer;
                }
            }
    
            public class MyRenderer extends RelativeLayout {
    
                public TextView textView;
    
                public MyRenderer(Context context) {
                    super(context);
                    setPadding(20, 20, 20, 20);
                    setBackgroundColor(0xFFFF0000);
    
                    RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
                            RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
                    rlp.addRule(CENTER_IN_PARENT);
                    textView = new TextView(context);
                    addView(textView, rlp);
                }
    
            }        }
    
0
répondu Vishavjeet Singh 2015-11-03 17:30:27

essayez cette spectaculaire page web @ pour commencer avec Activity & Fragment Transitions (part 1) . Ici, ils ont parlé de L'activité et des Transitions de fragments. Je n'ai pas essayé. Mon point de vue est que les Transitions de fragments sont meilleures et moins intensives en informatique, donc c'est un bon début. Et vous ne pouvez pas besoin de modifier les Barres d'outils, vous pouvez afficher/cacher.

un Autre bon DONC, le lien est @ Animer la transition entre les fragments , regardez la meilleure réponse. Dans ce post, ils ont parlé de objectanimateur .

une autre opinion est sur l'animation échantillon que vous avez posté, elle ne montre pas une animation lisse d'un art à l'autre. C'est moins impressionnant lorsque l'animation n'est pas fluide.

bonne chance, amusez-vous, tenez-nous au courant.

0
répondu The Original Android 2017-05-23 12:34:22