问题
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 hence I would like to make it scrollable.
So I added (based on Making TextView scrollable on Android) the following lines to my TextView
text.setMaxLines(5);
text.setVerticalScrollBarEnabled(true);
text.setMovementMethod(ScrollingMovementMethod.getInstance());
This works fine if I use the TextView in isolation but not when I put the TextView inside a ListView:
as soon as I do a vertical scroll, the events seem to be consumed by the ListView.
Any suggestions on how I can make this work?
The complete (test)activity is added below (no layout.xml)
public class TestScrollableTextView extends Activity
{
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
//add a ListView
ListView list = new ListView(this);
layout.addView(list);
list.setAdapter(new BaseAdapter()
{
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
TextView text = new TextView(TestScrollableTextView.this);
String s = "";
//add 10 lines of text, all but first are indented
for (int i = 0; i < 10; i++)
{
if(i>0) s+="\t";
s += "position "+position+"; line="+i+"\n";
}
text.setText(s);
text.setMaxLines(5);
text.setVerticalScrollBarEnabled(true);
text.setMovementMethod(ScrollingMovementMethod.getInstance());
return text;
}
@Override
public long getItemId(int position)
{
return 0;
}
@Override
public Object getItem(int position)
{
return null;
}
@Override
public int getCount()
{
return 20;
}
});
setContentView(layout);
}
}
回答1:
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);
回答2:
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;
}
回答3:
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;
}
}
回答4:
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;
}
}
来源:https://stackoverflow.com/questions/8121491/is-it-possible-to-add-a-scrollable-textview-to-a-listview