Make a ListView behaviour like a vertical Gallery
-
09-01-2021 - |
Domanda
I have the following code that make the ListView appears like a Vertical Gallery
public class VerticalGallery extends ListView {
private View currentDisplayingView;
private int currentPosition;
public VerticalGallery(Context context, List<Page> pages) {
super(context);
setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
currentDisplayingView = view;
currentPosition = position;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
setAdapter(new PageAdapter(context, pages));
setCacheColorHint(Color.TRANSPARENT);
}
public boolean onTouchEvent(MotionEvent evt) {
if (currentDisplayingView != null && currentDisplayingView.onTouchEvent(evt))
return true;
PageAdapter adapter = (PageAdapter) getAdapter();
if (currentPosition == adapter.list.size() - 1)
return false;
// TODO: Handle events and swipe somewhere
return super.onTouchEvent(evt);
}
public class PageAdapter extends BaseAdapter {
private Context context;
private List<Page> list;
public PageAdapter(Context c, List<Page> pages) {
context = c;
list = pages;
}
public int getCount() {
return list.size();
}
public Page getItem(int position) {
return list.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = getItem(position).generateView(context);
view.setLayoutParams(new ListView.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
return view;
}
}
}
But there's some behaviors that I need to simulate also:
- Centralize a View: When a new view come, I need to centralize it on my display.
- Fire
onItemSelected
events: I need those cause I dispatch events to the current view, and let theListView
scroll only when the currentView returns false on a touchEvent, I don't need exactly the ItemSelected events, this can be something similar. - And another question is, if the user swipe up, I should only translate one view (not several according to the speed of the gesture).
Any component that will let me do that will be a usefull answer also.
EDIT: Actually, I solved this problem with this solution Using Animation to swipe views but I'll keep this question open.
Soluzione 2
As I research, I developed this custom ScrollView that does pagination.
public class ScrollViewVertical extends ScrollView { private boolean paging;
public ScrollViewVertical(Context context) {
super(context);
}
public boolean onTouchEvent(MotionEvent evt) {
if (evt.getAction() == MotionEvent.ACTION_UP)
if (isPaging()){
centralizeContent();
return true;
}
return super.onTouchEvent(evt);
}
private void centralizeContent() {
int currentY = getScrollY() + getHeight() / 2;
ViewGroup content = (ViewGroup) getChildAt(0);
for (int i = 0; i < content.getChildCount(); i++) {
View child = content.getChildAt(i);
System.out.println(BoundsUtils.from(child));
if (child.getTop() < currentY && child.getBottom() > currentY) {
smoothScrollTo(0, child.getTop());
break;
}
}
}
}
Altri suggerimenti
how to implement both ontouch and also onfling in a same listview?
Read this question accepted answer about implementations of GestureListener class.
Make MyGestureListener class as inner in your current one or pass ListView object to the constructor of the MyGestureListener class.
In onFling() method measure the difference between initial and final touches like
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if(e1.getY() > e2.getY()) //1
{
int pos=(int)Math.floor(listView.getLastVisiblePosition/2);//2
if(pos < listView.getLastVisiblePosition())
listView.smoothScrollToPosition(pos--);//3
else
listView.smoothScrollToPosition(listView.getLastVisiblePosition());
}
else
{
int pos=(int)Math.floor(listView.getLastVisiblePosition/2);
if(pos < listView.getLastVisiblePosition && pos > listView.getFirstVisiblePosition())
listView.smoothScrollToPosition(pos++);
else
listView.smoothScrollToPosition(listView.getFirstVisiblePosition());
}
}
if
e1.getY() > e2.getY()
means that user fling-ed downwards. The differencee2.getY() - e1.getY()
is negative.Suppose that current position is the middle one.
Moving downwards for one position.
This code isn't tested and is response to your 3rd question. I'm just pointing you my idea.