I have a ListView where each row has a fixed height.
Every row contains, next to some images, a TextView.
Sometimes, the text I want to display is too large and henc
I can make this work by creating a subclass of ListView and override onTouchEvent as follows:
- I first check whether the MotionEvent is inside a childView
- if it is, I call the child's onTouchEvent
This does seem quite basic framework functionality so I'm surprised that this isn't handled by ListView itself. Am I missing something?
@Override
public boolean onTouchEvent(MotionEvent event)
{
//find correct child
View theChild = null;
boolean handled = false;
for (int i = 0; i < getChildCount(); i++)
{
View child = getChildAt(i);
Rect rect = new Rect();
child.getDrawingRect(rect);
offsetDescendantRectToMyCoords(child, rect);
if(rect.contains((int)event.getX(), (int)event.getY()))
{
theChild = child;
}
}
if(theChild!=null)
{
handled = theChild.onTouchEvent(event);
}
if(!handled) handled = super.onTouchEvent(event);
return handled;
}
Use this Custom to solve your issue.
public class ScrollableListView extends ListView {
public ScrollableListView(Context context) {
super(context);
}
public ScrollableListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollableListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.i("VerticalScrollview", "onInterceptTouchEvent: DOWN super false");
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
return false; // redirect MotionEvents to ourself
case MotionEvent.ACTION_CANCEL:
Log.i("VerticalScrollview", "onInterceptTouchEvent: CANCEL super false");
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
Log.i("VerticalScrollview", "onInterceptTouchEvent: UP super false");
return false;
default:
Log.i("VerticalScrollview", "onInterceptTouchEvent: " + action);
break;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction());
return true;
}
}
getLineCount and getLineHieght and check if the Text is larger than the TextView.
if you use this code, the listView can be scrolled by touching anywhere other than the TextView with (boolean)isLarger = true.
text.setText(s);
text.setMaxLines(100);
text.setVerticalScrollBarEnabled(true);
text.setMovementMethod(new ScrollingMovementMethod());
OnTouchListener listener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean isLarger;
isLarger = ((TextView) v).getLineCount()
* ((TextView) v).getLineHeight() > v.getHeight();
if (event.getAction() == MotionEvent.ACTION_MOVE
&& isLarger) {
v.getParent().requestDisallowInterceptTouchEvent(true);
} else {
v.getParent().requestDisallowInterceptTouchEvent(false);
}
return false;
}
};
text.setOnTouchListener(listener);
A better way is probably to create your own MyTextView as follows and to call requestDisallowInterceptTouchEvent. By doing so, you indicate to the listview that it' shouldn't intercept events.
class MyTextView extends TextView
{
public MyTextView(Context context)
{
super(context);
// TODO Auto-generated constructor stub
}
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
boolean ret;
ret = super.dispatchTouchEvent(event);
if(ret)
{
list.requestDisallowInterceptTouchEvent(true);
}
return ret;
}
}