J'essaie de reproduire l'application Google Plus dans mon projet, car elle semble être la référence actuelle.
L’effet listview lors du défilement est vraiment agréable et j’aimerais faire quelque chose de similaire.
J'ai commencé avec LayoutAnimationController http://Android-er.blogspot.be/2009/10/listview-and-listactivity-layout.html
LayoutAnimationController controller
= AnimationUtils.loadLayoutAnimation(
this, R.anim.list_layout_controller);
getListView().setLayoutAnimation(controller);
et cela semble mauvais, car tous les éléments ne sont pas animés:
J'ai donc fini par utiliser le getView de l'adaptateur et utiliser ceci:
AnimationSet set = new AnimationSet(true);
Animation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(800);
set.addAnimation(animation);
animation = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 1.0f,Animation.RELATIVE_TO_SELF, 0.0f
);
animation.setDuration(600);
set.addAnimation(animation);
row.startAnimation(set);
Le résultat est génial et j'en suis vraiment content!
Malheureusement, cela ne fonctionne que lorsque je fais défiler de haut en bas de la liste!
Je veux le faire fonctionner en faisant défiler de l'autre côté, je dois changer un peu le TranslateAnimation.
Alors ma question, y at-il un moyen de détecter si je fais défiler vers le haut ou vers le bas dans mon adaptateur?
Assignez un OnScrollListener
à votre ListView
. Créez un drapeau qui indique si l'utilisateur fait défiler vers le haut ou vers le bas. Définissez une valeur appropriée pour le drapeau en vérifiant si la position actuelle de l'élément visible premier est égale ou supérieure à la position précédente visible de premier. Mettez cette vérification à l'intérieur de onScrollStateChanged()
.
Exemple de code:
private int mLastFirstVisibleItem;
private boolean mIsScrollingUp;
public void onScrollStateChanged(AbsListView view, int scrollState) {
final ListView lw = getListView();
if (view.getId() == lw.getId()) {
final int currentFirstVisibleItem = lw.getFirstVisiblePosition();
if (currentFirstVisibleItem > mLastFirstVisibleItem) {
mIsScrollingUp = false;
} else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
mIsScrollingUp = true;
}
mLastFirstVisibleItem = currentFirstVisibleItem;
}
}
Vérifiez si mIsScrollingUp
est vrai ou faux dans getView()
et attribuez les animations en conséquence.
J'ai fini par faire ceci:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.i("",position+" - "+lastposition);
if (position >= lastposition)
animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 1.0f,
Animation.RELATIVE_TO_SELF, 0.0f);
else
animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, -1.0f,
Animation.RELATIVE_TO_SELF, 0.0f);
animation.setDuration(600);
set.addAnimation(animation);
row.startAnimation(set);
lastposition = position;
}
Solution plus complexe (travailler avec la hauteur des éléments longs dans listview)
Créer une liste personnalisée
public class ScrollDetectingListView extends ListView {
public ScrollDetectingListView(Context context) {
super(context);
}
public ScrollDetectingListView(Context context, AttributeSet attrs) {
super(context,attrs);
}
public ScrollDetectingListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
//we need this protected method for scroll detection
public int getVerticalScrollOffset() {
return computeVerticalScrollOffset();
}
}
Ignorer onScroll
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
private int mInitialScroll = 0;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int scrolledOffset = listView.getVerticalScrollOffset();
if (scrolledOffset!=mInitialScroll) {
//if scroll position changed
boolean scrollUp = (scrolledOffset - mInitialScroll) < 0;
mInitialScroll = scrolledOffset;
}
}
});
La réponse acceptée ne "détecte" pas vraiment le défilement vers le haut ou le bas. Cela ne fonctionnera pas si l'élément visible actuel est vraiment énorme. Utiliser onTouchListener
est la voie à suivre.
Voici l'extrait de code que j'ai utilisé:
listView.setOnTouchListener(new View.OnTouchListener() {
float initialY, finalY;
boolean isScrollingUp;
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
switch(action) {
case (MotionEvent.ACTION_DOWN):
initialY = event.getY();
case (MotionEvent.ACTION_UP):
finalY = event.getY();
if (initialY < finalY) {
Log.d(TAG, "Scrolling up");
isScrollingUp = true;
} else if (initialY > finalY) {
Log.d(TAG, "Scrolling down");
isScrollingUp = false;
}
default:
}
if (isScrollingUp) {
// do animation for scrolling up
} else {
// do animation for scrolling down
}
return false; // has to be false, or it will freeze the listView
}
});
Essaye ça . J'espère que ça t'aide . Logique de @Gal Rom Answer.
lv.setOnScrollListener(new OnScrollListener() {
private int mLastFirstVisibleItem;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(mLastFirstVisibleItem<firstVisibleItem)
{
Log.i("SCROLLING DOWN","TRUE");
}
if(mLastFirstVisibleItem>firstVisibleItem)
{
Log.i("SCROLLING UP","TRUE");
}
mLastFirstVisibleItem=firstVisibleItem;
}
});
Voici mon approche: Vous obtenez un retour plus immédiat sur le nombre de fois que vous avez fait défiler: OnScroll
, vous pouvez simplement obtenir la position de tête du premier élément de votre liste. Il est assez fiable d’obtenir immédiatement des informations sur la position réelle du défilement.
listView.getChildAt(0).getTop()
list.setOnScrollListener(new OnScrollListener() {
int last_item;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(last_item<firstVisibleItem+visibleItemCount-1){
System.out.println("List is scrolling upwards");
}
else if(last_item>firstVisibleItem+visibleItemCount-1){
System.out.println("List is scrolling downwards");
}
last_item = firstVisibleItem+visibleItemCount-1;
}
});
En fonction de la position du dernier élément visible, je décide si Listview est en train de monter ou de descendre.
Solution générale qui ne repose pas sur des positions de vues/etc. Il suffit de vérifier le décalage de défilement vertical et de le comparer au décalage de défilement précédent. Si la nouvelle valeur est supérieure à l'ancienne, l'utilisateur fait défiler l'écran vers le bas, et inversement.
// [START check vertical scroll direction]
int oldScrollOffset = 0;
listView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View view, int i, int i1, int i2, int i3) {
Boolean scrollDirectionDown;
int newScrollOffset = listView.computeVerticalScrollOffset();
if (newScrollOffset > oldScrollOffset) {
scrollDirectionDown = true;
} else {
scrollDirectionDown = false;
}
oldScrollOffset = newScrollOffset;
if (scrollDirectionDown) {
// Update accordingly for scrolling down
Log.d(TAG, "scrolling down");
} else {
// Update accordingly for scrolling up
Log.d(TAG, "scrolling up");
}
});
// [END check vertical scroll direction]
J'ai utilisé cette solution beaucoup plus simple:
public class ScrollDetectingListView extends ListView
...
setOnScrollListener( new OnScrollListener()
{
private int mInitialScroll = 0;
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount)
{
int scrolledOffset = computeVerticalScrollOffset();
boolean scrollUp = scrolledOffset > mInitialScroll;
mInitialScroll = scrolledOffset;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
}