【问题标题】:Is it possible to add a scrollable TextView to a ListView?是否可以将可滚动的 TextView 添加到 ListView?
【发布时间】:2014-12-19 21:47:50
【问题描述】:

我有一个 ListView,其中每一行都有固定的高度。
每行在一些图像旁边都包含一个 TextView。
有时,我想要显示的文本太大,因此我想让它可滚动。
所以我添加(基于Making TextView scrollable on Android)以下行到我的TextView

text.setMaxLines(5);
text.setVerticalScrollBarEnabled(true);
text.setMovementMethod(ScrollingMovementMethod.getInstance());

如果我单独使用 TextView,但当我将 TextView 放在 ListView 中时,这可以正常工作:
一旦我进行垂直滚动,事件似乎就被 ListView 消耗掉了。

关于如何完成这项工作的任何建议?

下面添加完整的(测试)activity(没有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);

  }
}

【问题讨论】:

    标签: android android-layout android-listview textview android-scroll


    【解决方案1】:

    getLineCount 和 getLineHieght 并检查 Text 是否大于 TextView。

    如果你使用这个代码,listView 可以通过触摸 TextView 以外的任何地方滚动,并且 (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);
    

    【讨论】:

    • 天才!无论TextView 中的文本如何,是否有任何理由不只在每个触摸事件上调用v.getParent().requestDisallowInterceptTouchEvent(true);?它似乎也是这样工作的:我的是一个TextView(垂直)在一个ViewPager(水平)里面一个RecyclerView(垂直);即使没有移动方法。
    【解决方案2】:

    我可以通过创建 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;
        }
    

    【讨论】:

      【解决方案3】:

      更好的方法可能是创建自己的 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;
        }
      
      }
      

      【讨论】:

      • 嗨,list.requestDisallowInterceptTouchEvent(true) 中出现红色下划线错误无法解析方法。
      • list 是一个 ListView 对象,它有一个 View.requestDisallowInterceptTouchEvent 方法(参见developer.android.com/reference/android/view/…
      【解决方案4】:

      使用此自定义来解决您的问题。

      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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-26
        相关资源
        最近更新 更多