Можно ли добавить прокручиваемый TextView в ListView?
У меня есть ListView, где каждая строка имеет фиксированную высоту.
Каждая строка содержит рядом с некоторыми изображениями TextView.
Иногда текст, который я хочу отобразить, слишком велик, и поэтому я хотел бы сделать его прокручиваемым.
Поэтому я добавил (на основе прокрутки TextView на Android) следующие строки в мой TextView
text.setMaxLines(5);
text.setVerticalScrollBarEnabled(true);
text.setMovementMethod(ScrollingMovementMethod.getInstance());
Это прекрасно работает, если я использую TextView изолированно, но не тогда, когда я помещаю TextView внутри ListView:
как только я делаю вертикальную прокрутку, кажется, что события используются ListView.
Любые предложения о том, как я могу сделать эту работу?
Полное (тестовое) действие добавлено ниже (без 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);
}
}
4 ответа
Возможно, лучшим способом будет создать свой собственный MyTextView следующим образом и вызвать requestDisallowInterceptTouchEvent. Тем самым вы указываете списку, что он не должен перехватывать события.
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;
}
}
getLineCount и getLineHieght и проверьте, больше ли Text, чем TextView.
Если вы используете этот код, listView можно прокрутить, коснувшись в любом месте, кроме TextView, с помощью (логического)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);
Используйте этот Custom для решения вашей проблемы.
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;
}
}
Я могу сделать эту работу, создав подкласс ListView и переопределив onTouchEvent следующим образом:
- сначала я проверяю, находится ли MotionEvent внутри childView
- если это так, я вызываю ребенка onTouchEvent
Это кажется довольно базовой функциональностью фреймворка, поэтому я удивлен, что это не обрабатывается самим ListView. Я что-то пропустил?
@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;
}