5

滚动前: 在此处输入图像描述

滚动期间: 在此处输入图像描述

我在滚动过程中的期望: 在此处输入图像描述

我对 Horizo​​ntalScrollView 有疑问。当我从此视图中选择一个元素时,我通过调用将焦点设置到该元素:

else if (v.getParent() == candidatesScrollView.getChildAt(0))
{
    Button candidateButton = (Button) v;
    v.requestFocusFromTouch();
    v.setSelected(true);
            (...)
}

之后,当我滚动列表而不选择其他元素时,我失去了先前选择的元素的焦点。我对这个主题进行了一些研究,但没有适合我的解决方案......如何滚动我的 Horizo​​ntalScrollList 而不会失去所选元素的焦点?任何帮助表示赞赏。自从我提出这个问题以来已经大约 14 天了,但仍然没有找到解决方案。请帮忙。

这是我的 XML 的一部分:

<HorizontalScrollView
        android:id="@+id/CandidatesHorizontalScrollView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/linearLayout2"
        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:visibility="gone" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/horizontalscrollview1_button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textSize="25sp" />

        (...)
        // 11 more buttons
    </LinearLayout>

</HorizontalScrollView>

更新

我当前的解决方案#1(无法正常工作): 滚动后,然后再次滚动(例如向后滚动),滚动从所选元素开始。

我创建了自定义 Horizo​​ntalScrollView 类,其中我覆盖了 onTouchEvent() 方法。我不认为这是这样做的最佳方式,因为在这种情况下,我每次移动一个像素时都必须进行计算。例如,如果我将 toast.show() 添加到下面的方法中,它将尝试显示与我移动像素一样多的 toast(如果我移动 10 个像素,它将尝试显示 10 个 Toast)。无论如何,它对我有用,并且选择和重点保持不变。

请帮助我修改此代码,以便最终为该已知问题提供一个好的答案:

@Override
public boolean onTouchEvent(MotionEvent ev)
{
    int i = 0;
    Button button = null;
    for (; i < 11; i++)
    {
        button = (Button)((LinearLayout)getChildAt(0)).getChildAt(i);
        if(button.isSelected())
            break;
    }
    super.onTouchEvent(ev);
    button.setSelected(true);
    button.requestFocusFromTouch();

    return true;
}

为了确保上面的代码能够正常工作,你需要在你的 Horizo​​ntalScrollView 中一次只选择一个项目,即当你按下不同的按钮时,你需要将前一个设置为 setSelected(false)

我当前的解决方案#2(无法正常工作):

我尝试实施的解决方案#2,认为第一个不够优雅,涉及到手势检测器的使用。在我的自定义 Horizo​​ntalListView 类中,我添加了以下代码:

构造函数:

public MyHorizontalScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
    gestureDetector = new GestureDetector(context, new MyHorizontalScrollViewGestureDetector());
    this.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            gestureDetector.onTouchEvent(event);

            return true;
        }
    });
    // TODO Auto-generated constructor stub
}

MyHorizo​​ntalScrollViewGestureDetector 内部类:

public class MyHorizontalScrollViewGestureDetector extends SimpleOnGestureListener
    {

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
        {
            //Here code similar like that one in solution #1
            //But the View is not scrolling, even without that code 
            super.onScroll(e1, e2, distanceX, distanceY);

            return true; 
        }
    }   

但是,该列表不会随着该解决方案滚动。我可以添加到 onScroll 方法:

ScrollBy((int)positionX, (int)positionY);

这使得列表会滚动,但不是很好,它有时会冻结。我想知道为什么超级不调用滚动。方法。

我当前的解决方案#3(工作,但它是走动):

因为解决方案 1 和 2 都不起作用,所以我决定不再专注于玩。我现在所做的是,每当我单击它以及每次更改为不同的 Button 时都更改 Button Drawable。我使用与用于聚焦按钮(Holo)相同的 Drawable。在那种情况下,我不必担心在 Horizo​​ntalScrollView 中滚动。这个解决方案是一种临时解决方案,所以我期待任何评论、建议和编辑。

4

4 回答 4

1

以下解决方案是否适用(我从这里得到了这个想法):

您可能想尝试创建自己的自定义类来扩展HorizontalScrollView和覆盖该onScrollChanged()函数:

public class TestHorizontalScrollView extends HorizontalScrollView {

    public TestHorizontalScrollView(Context context) {
        super(context);
    }


    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        // TODO Auto-generated method stub
        Log.i("Scrolling", "X from ["+oldl+"] to ["+l+"]");
        Button button = null;
        for (; i < 11; i++)
        {
          button = (Button)((LinearLayout)getChildAt(0)).getChildAt(i);
          if(button.isSelected())
            break;
        }
        button.setSelected(true);
        button.requestFocusFromTouch();

        super.onScrollChanged(l, t, oldl, oldt);
    }

}

现在您已经检测到滚动(我们正在谈论其中之一HorizontalScrollView),您可以再次设置相应按钮的选定状态。你能试试这个解决方案,看看它是否有效。我对这个问题的解决方案很感兴趣,因为这个问题也很有趣。

无论如何,我设法找到了以下文章。他们在那里声明:

想象一个简单的应用程序,例如 ApiDemos,它显示了一个文本项列表。用户可以使用轨迹球在列表中自由导航,也可以使用手指滚动和翻动列表。这种情况下的问题是选择。如果我选择列表顶部的一个项目,然后将列表扔到底部,选择会发生什么?它应该保留在项目上并滚出屏幕吗?在这种情况下,如果我决定用轨迹球移动选择会发生什么?或者更糟糕的是,如果我按下轨迹球对当前选定的项目进行操作,该项目不再显示在屏幕上。经过仔细考虑,我们决定完全删除选择。

在触摸模式下,没有焦点,也没有选择。一旦用户进入触摸模式,网格列表中的任何选定项目都将变为未选中状态。类似地,当用户进入触摸模式时,任何有焦点的小部件都会变得没有焦点。下图说明了当用户在使用轨迹球选择项目后触摸列表时会发生什么。

无论如何,那里的陈述并没有让我高兴,我进一步发现:

android:focusable="true"
android:focusableInTouchMode="true"

也设置android:clickable="true"(你不妨设置android:focusable="true"LinearLayout)。

尝试将它们添加到按钮和包含它们的布局中。尝试一切。

我会尽量支持你。

干杯

于 2013-07-03T14:52:49.507 回答
0

我记得滚动视图有一个问题,我认为这与您遇到的问题相似。

我想出的解决方案是覆盖类onRequestFocusInDescendants中的方法HorizontalScrollViewHorizontalScrollView如果您还没有这样做,这需要您创建自己的扩展类。

就我而言,我总是从该方法返回 true。这告诉调用者您已经处理了焦点更改,因此它不应该尝试进一步做任何事情。

@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
  return true;
}

根据您的要求,您可能会发现只有在某些条件下(例如当滚动正在进行时)才需要返回 true,否则将调用转发给超类。

于 2013-07-07T23:23:47.607 回答
0

这个问题除了自定义的方法之外没有答案,因为您可能已经做过更改可绘制对象之类的操作。原因是当你滑动的时候,焦点转到了 Horizo​​ntalScroll,你只能关注一个项目,关注多个视图是没有意义的。因此,要么实现一个可绘制对象(您似乎已经完成了),要么扩展一个复选框并覆盖该功能,以便在聚焦时检查并更改外观。

于 2013-07-08T23:36:59.060 回答
0

我找到了解决我的问题的方法。您可以查看更新后的问题以了解详细信息。基本上,我决定使用 Drawable 选择器,而不是使用焦点,这更容易。

于 2013-07-11T01:22:49.057 回答