Is it possible to add a scrollable TextView to a ListView?

99封情书 提交于 2019-12-18 17:14:14

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!