可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to mimic the Google Plus application in my project, as it seems to be the reference now.
The listview effect when scrolling is really nice and I would like to do something similar.
I have started with the 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);
and that seems bad, as not all the elements are animated:
So I ended up by using the getView of the adapter and using this:
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);
The result is awesome and I am really happy with it!
Unfortunately, it only works when I scroll from top to bottom of the list!
I want to make it work when scrolling on the other side, I need to change a little bit the TranslateAnimation.
So my question, is there a way to detect if I scroll upwards or downwards in my adapter?
回答1:
Assign an OnScrollListener
to your ListView
. Create a flag which indicates whether the user is scrolling up or down. Set an appropriate value to the flag by checking if the current first visible item position equals to more or less than the previous first visible item position. Put that check inside onScrollStateChanged()
.
Sample 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;
}
}
Check if mIsScrollingUp
is true or false in getView()
, and assign the animations accordingly.
回答2:
I ended up by doing this:
@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;
}
回答3:
More complex solution (working with long items height in listview)
Create custom listview
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();
}
}
Override 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;
}
}
});
回答4:
The accepted answer doesn't really "detect" scrolling up or down. It won't work if the current visible item is really huge. Using onTouchListener
is the way to go.
This is the code snippet I used:
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
}
});
回答5:
Try this . I hope it helps you . Logic From @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;
}
});
回答6:
Here's my approach: It gets you more immediate feedback on how much you've scrolled:
OnScroll
, you can just get the Top position of the first item in your list. It's a pretty reliable to get actual scroll position information immediately.
listView.getChildAt(0).getTop()
回答7:
I've used this much simpler solution:
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) {
}
}
回答8:
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;
}
});
Based on the position of the last visible item i decide whether Listview is going up or down.
回答9:
General solution that doesn't rely on positions of views/etc. Just check the vertical scroll offset and compare it to the previous scroll offset. If the new value is greater than the old the user is scrolling down, and vice-versa.
// [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]