Reputation: 1771
So this is not a tecnical question with code but more on some thoughts. I am new to android developing and because of that I am not completely familiar with a lot of what it has to offer.
I have a list of items on the screen and you can scroll up and down to view the different items.
My issue came up when I decided to have the items be able to slide left and right to reveal a settings like panal with a few optons below them(each item has its own settings below it, not a setting screen for all items kind of deal). I looked around for different ways to do this but cant seem to find one that works. What I am thinking so far is to have a HorizonalScrollView
with my item in it with the setting menu to the left or right off the screen, but when I put my text area in the HorizonalScrollView
, it only takes up half the screen, so I can fit two side by side, not what I wanted and the end result wont be what I imagined. I really would like a solution that allows for the setting to be under the item, so when you push it out of the way it reveals the settings.
Is there a better way or should I just continue trying to make my HorizonalScrollView
work, any guides or thought on how I could go about this would be greatly appreciated.
Went though my apps to see if I could find one that has something similar, gmail app has it. Here is a link to an image that gives you an idea, after you slide the item to the side it brings up an undo or archive buttons in the place of the item as if they were hiding under the list item you swiped away
Upvotes: 0
Views: 1256
Reputation: 39836
it's quite an interesting topic this question. And be prepared to do a certain amount of custo stuff.
First of all, drop the HorizonalScrollView, I don't think it will help you. The layout of each item should be something like this (pseudo-code, you can build the XML yourself =] ):
FrameLayout
RelativeLayout id:topContent background:someSolidColor
// inside this RelativeLayout, the stuff that is visible on the ListView
RelativeLayout id:bottomContent
// inside this RelativeLayout, the stuff that is behind the content
/FrameLayout
that way you will be literally putting one thing on top of the other. Also note that the topContent have a background with a solid color. If you do not specify any background, both RelativeLayouts will be visible. Also note that I used RelativeLayout, just because I like them, and I like their flexibility, but this will depend on the content of your list view and your settings.
And now is when things get fun, you'll need a GestureDetector to detect the finger sliding and you'll use that value to generate a margin offset on the id:topContent
.
You can create a TouchListener like this:
public class MySlideListener extends View.OnTouchListener{
private View v;
private GestureDetector gestureDetector;
public MySlideListener (View v){
this.v = v;
gestureDetector = new GestureDetector(v.getContext(), myGestureListener);
}
public boolean onTouch (View v, MotionEvent event){
return gestureDetector.onTouchEvent(event);
}
private SimpleOnGestureListener myGestureListener = new SimpleOnGestureListener(){
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){
// now here we make the view scroll
MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
lp.leftMargin = distanceX;
lp.rightMargin = -distanceX;
// You might need to call view.requestLayout();
// but first give it a try without it
// This part of the method for processing the horizontal
// offset can (and should) be further developed to add some
// 'snap-in' or transparency functionality to make the whole
// concept work better.
// But this code should give you a proof of concept on how to deal with stuff.
// The important part is that now you have a call back that have access
// to the view during onScroll.
// Also might be necessary to enable/disable the bottomContent view
// in order for it to be not clickable whilst not visible.
return true;
}
}
}
and then set a new of those listeners for each topContent
of your ListView (probably inside the getView from the adapter) with topContentView.setOnTouchListener(new MySlideListener(topContentView));
Please keep in mind that I typed all this code by heart and is 100% untested!
edit:
The above code is the correct direction, but it's a 100% untested thing. Now the code below, I've just compiled, tested, and this code works!
This class is also a bit more efficient as you can create only one and apply the same instance to all the items created on your adapter. You can see it's getting the view to scroll on the touch event.
public class MySlideListener implements View.OnTouchListener {
private View view;
private ListView listView;
private GestureDetector gestureDetector;
public MySlideListener(ListView lv) {
listView = lv;
gestureDetector = new GestureDetector(lv.getContext(), myGestureListener);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
view = v;
gestureDetector.onTouchEvent(event);
return true;
}
private SimpleOnGestureListener myGestureListener = new SimpleOnGestureListener() {
private int origLeft, origRight;
public boolean onDown(MotionEvent e) {
MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
origLeft = lp.leftMargin;
origRight = lp.rightMargin;
return true;
};
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
listView.requestDisallowInterceptTouchEvent(true);
MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
lp.leftMargin = (int) (origLeft + (e2.getRawX() - e1.getRawX()));
lp.rightMargin = (int) (origRight - (e2.getRawX() - e1.getRawX()));
view.requestLayout();
return true;
};
};
}
Upvotes: 2