64 votes

Élément de liste de défilement de l'animation ("UIKit Dynamique")

Je suis d'essayer d'animer l' ListView articles quand un parchemin. Plus précisément, je suis en train d'essayer d'imiter le défilement des animations à partir de l'application iMessage sur iOS 7. J'ai trouvé un exemple similaire en ligne:

moments-ios7.gif

Pour préciser, je suis en train de réaliser le "fluide" effet de mouvement sur les éléments lorsque l'utilisateur fait défiler, pas de l'animation lorsqu'un nouvel élément est ajouté. J'ai tenté de modifier le point de Vue dans mon BaseAdapter et j'ai regardé dans l' AbsListView source pour voir si j'arrivais à joindre un AccelerateInterpolator quelque part qui permettrait de régler le tirage coordonnées envoyées pour les enfants de Vues (si c'est même la façon dont AbsListView est conçu). J'ai été incapables de faire aucun progrès à ce jour.

Quelqu'un a une idée de la façon de reproduire ce comportement?


Pour l'enregistrement à l'aide avec googler: ceci est appelé "UIKit Dynamique" sur ios.

Comment reproduire les Messages de rebondir bulles dans iOS 7

Il est intégré aux dernières versions du logiciel iOS. Cependant, il est encore un peu difficile à utiliser. (2014) C'est le post sur elle tout le monde copies:largement copiés de l'article Étonnamment, UIKit Dynamique est uniquement disponible sur l'apple de la collection "vue", et non pas sur apple "table view" de sorte que tous les iOS debs sont d'avoir à convertir des trucs à partir de la vue de la table de la collection "vue"

La bibliothèque de tout le monde est en utilisant comme point de départ est BPXLFlowLayout, puisque cette personne assez bien fendu la copie de la sensation de l'iphone des messages texte d'application. En fait, si vous étiez le portage vers Android je suppose que vous pourriez utiliser les paramètres pour obtenir la même sensation. Pour info, j'ai remarqué dans mon android fone collection, téléphones HTC, sur leur INTERFACE utilisateur. Espérons que cela aide. Android rochers!

17voto

simekadam Points 2025

Cette application fonctionne très bien. Il y a un scintillement, bien que, probablement en raison de l'altération des indices lorsque l'adaptateur d'ajouter de nouveaux points de vue vers le haut ou le bas..Qui pourraient être résolus en regardant les changements dans l'arbre et en privilégiant les indices à la volée..

public class ElasticListView extends GridView implements AbsListView.OnScrollListener,      View.OnTouchListener {

private static int SCROLLING_UP = 1;
private static int SCROLLING_DOWN = 2;

private int mScrollState;
private int mScrollDirection;
private int mTouchedIndex;

private View mTouchedView;

private int mScrollOffset;
private int mStartScrollOffset;

private boolean mAnimate;

private HashMap<View, ViewPropertyAnimator> animatedItems;


public ElasticListView(Context context) {
    super(context);
    init();
}

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

public ElasticListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

private void init() {
    mScrollState = SCROLL_STATE_IDLE;
    mScrollDirection = 0;
    mStartScrollOffset = -1;
    mTouchedIndex = Integer.MAX_VALUE;
    mAnimate = true;
    animatedItems = new HashMap<>();
    this.setOnTouchListener(this);
    this.setOnScrollListener(this);

}


@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
    if (mScrollState != scrollState) {
        mScrollState = scrollState;
        mAnimate = true;

    }
    if (scrollState == SCROLL_STATE_IDLE) {
        mStartScrollOffset = Integer.MAX_VALUE;
        mAnimate = true;
        startAnimations();
    }

}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    if (mScrollState == SCROLL_STATE_TOUCH_SCROLL) {

        if (mStartScrollOffset == Integer.MAX_VALUE) {
            mTouchedView = getChildAt(mTouchedIndex - getPositionForView(getChildAt(0)));
            if (mTouchedView == null) return;

            mStartScrollOffset = mTouchedView.getTop();
        } else if (mTouchedView == null) return;

        mScrollOffset = mTouchedView.getTop() - mStartScrollOffset;
        int tmpScrollDirection;
        if (mScrollOffset > 0) {

            tmpScrollDirection = SCROLLING_UP;

        } else {
            tmpScrollDirection = SCROLLING_DOWN;
        }

        if (mScrollDirection != tmpScrollDirection) {
            startAnimations();
            mScrollDirection = tmpScrollDirection;
        }


        if (Math.abs(mScrollOffset) > 200) {
            mAnimate = false;
            startAnimations();
        }
        Log.d("test", "direction:" + (mScrollDirection == SCROLLING_UP ? "up" : "down") + ", scrollOffset:" + mScrollOffset + ", toucheId:" + mTouchedIndex + ", fvisible:" + firstVisibleItem + ", " +
            "visibleItemCount:" + visibleItemCount + ", " +
            "totalCount:" + totalItemCount);
        int indexOfLastAnimatedItem = mScrollDirection == SCROLLING_DOWN ?
            getPositionForView(getChildAt(0)) + getChildCount() :
            getPositionForView(getChildAt(0));

        //check for bounds
        if (indexOfLastAnimatedItem >= getChildCount()) {
            indexOfLastAnimatedItem = getChildCount() - 1;
        } else if (indexOfLastAnimatedItem < 0) {
            indexOfLastAnimatedItem = 0;
        }

        if (mScrollDirection == SCROLLING_DOWN) {
            setAnimationForScrollingDown(mTouchedIndex - getPositionForView(getChildAt(0)), indexOfLastAnimatedItem, firstVisibleItem);
        } else {
            setAnimationForScrollingUp(mTouchedIndex - getPositionForView(getChildAt(0)), indexOfLastAnimatedItem, firstVisibleItem);
        }
        if (Math.abs(mScrollOffset) > 200) {
            mAnimate = false;
            startAnimations();
            mTouchedView = null;
            mScrollDirection = 0;
            mStartScrollOffset = -1;
            mTouchedIndex = Integer.MAX_VALUE;
            mAnimate = true;
        }
    }
}

private void startAnimations() {
    for (ViewPropertyAnimator animator : animatedItems.values()) {
        animator.start();
    }
    animatedItems.clear();
}

private void setAnimationForScrollingDown(int indexOfTouchedChild, int indexOflastAnimatedChild, int firstVisibleIndex) {
    for (int i = indexOfTouchedChild + 1; i <= indexOflastAnimatedChild; i++) {
        View v = getChildAt(i);
        v.setTranslationY((-1f * mScrollOffset));
        if (!animatedItems.containsKey(v)) {
            animatedItems.put(v, v.animate().translationY(0).setDuration(300).setStartDelay(50 * i));
        }

    }
}

private void setAnimationForScrollingUp(int indexOfTouchedChild, int indexOflastAnimatedChild, int firstVisibleIndex) {
    for (int i = indexOfTouchedChild - 1; i > 0; i--) {
        View v = getChildAt(i);

        v.setTranslationY((-1 * mScrollOffset));
        if (!animatedItems.containsKey(v)) {
            animatedItems.put(v, v.animate().translationY(0).setDuration(300).setStartDelay(50 * (indexOfTouchedChild - i)));
        }

    }
}


@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            Rect rect = new Rect();
            int childCount = getChildCount();
            int[] listViewCoords = new int[2];
            getLocationOnScreen(listViewCoords);
            int x = (int)event.getRawX() - listViewCoords[0];
            int y = (int)event.getRawY() - listViewCoords[1];
            View child;
            for (int i = 0; i < childCount; i++) {
                child = getChildAt(i);
                child.getHitRect(rect);
                if (rect.contains(x, y)) {
                    mTouchedIndex = getPositionForView(child); 
                    break;
                }
            }
            return false;

    }
    return false;

}

}

16voto

Sagar Shah Points 824

Essayez en mettant dans votre getView() la méthode Juste avant de retourner votre convertView:

Animation animationY = new TranslateAnimation(0, 0, holder.llParent.getHeight()/4, 0);
animationY.setDuration(1000);
Yourconvertview.startAnimation(animationY);  
animationY = null; 

Où llParent = RootLayout qui se compose de votre Ligne Personnalisée Élément.

16voto

Justin Pollard Points 431

J'ai pris quelques minutes pour explorer cette voie et on dirait qu'il peut être fait assez facilement avec l'API 12 et au-dessus (j'espère que je ne suis pas manque quelque chose ...). Pour obtenir la carte de base de l'effet, il suffit de quelques lignes de code à la fin de getView() de votre Carte à droite avant de revenir à la liste. Voici l'intégralité de la Carte:

    public class MyAdapter extends ArrayAdapter<String>{

        private int mLastPosition;

        public MyAdapter(Context context, ArrayList<String> objects) {
            super(context, 0, objects);
        }

        private class ViewHolder{
            public TextView mTextView;
        }

        @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder holder;

            if (convertView == null) {
                holder = new ViewHolder();
                convertView = LayoutInflater.from(getContext()).inflate(R.layout.grid_item, parent, false);
                holder.mTextView = (TextView) convertView.findViewById(R.id.checkbox);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            holder.mTextView.setText(getItem(position));

            // This tells the view where to start based on the direction of the scroll.
            // If the last position to be loaded is <= the current position, we want
            // the views to start below their ending point (500f further down).
            // Otherwise, we start above the ending point.
            float initialTranslation = (mLastPosition <= position ? 500f : -500f);

            convertView.setTranslationY(initialTranslation);
            convertView.animate()
                    .setInterpolator(new DecelerateInterpolator(1.0f))
                    .translationY(0f)
                    .setDuration(300l)
                    .setListener(null);

            // Keep track of the last position we loaded
            mLastPosition = position;

            return convertView;
        }


    }

Note que je vais garder la trace de la dernière position à charger (mLastPosition) afin de déterminer si d'animer les points de vue de bas en haut (si le défilement vers le bas) ou vers le bas à partir du haut (si nous sommes de défilement vers le haut).

La chose merveilleuse est, vous pouvez le faire beaucoup plus simplement en modifiant la première convertView propriétés (par exemple convertView.setScaleX(float scale)) et la convertView.animate() de la chaîne (par exemple .scaleX(float)).

enter image description here

1voto

SDJMcHattie Points 828

C'est honnêtement va être beaucoup de travail et tout à fait mathématiquement intense, mais j'aurais pensé que vous pourriez faire de l'élément de la liste de mises en page de rembourrage en haut et en bas et que vous pouvez ajuster qui rembourrage pour chaque élément, de sorte que les éléments individuels sont devenus plus ou moins espacées. Comment vous permettrait de suivre dans quelle mesure et comment vous le savez la vitesse à laquelle les éléments sont décalés, eh bien ce serait la partie la plus difficile.

-1voto

Dyna Points 1529

Ce que je comprends de ce que vous cherchez est un effet de parallaxe.

Cette réponse est vraiment complet et je pense que cela peut vous aider beaucoup.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X