在水平ScrollView中滚动会失去焦点元素的焦点,

时间:2013-06-17 04:38:33

标签: android list scroll focus scrollview

滚动前: enter image description here

滚动期间 enter image description here

我在滚动期间的期望: enter image description here

我的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()添加到下面的方法中,它将尝试显示尽可能多的我移动像素的吐司(如果我移动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)

MY CURRENT SOLUTION#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时都会更改Button Drawable。我使用与用于聚焦按钮(Holo)相同的Drawable。在这种情况下,我不必担心在Horizo​​ntalScrollView中滚动。这个解决方案是一种循环,所以我期待任何评论,建议和编辑。

4 个答案:

答案 0 :(得分:1)

以下解决方案是否适用(我从here获取了想法):

您可能想尝试创建自己的自定义类,扩展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)您可以再次设置相应按钮的选定状态。你可以试试这个解决方案,看看它是否有效。我对解决这个问题很感兴趣,因为这个问题也非常有趣。

无论如何,我设法找到了following article。他们在那里说:

  

想象一下一个简单的应用程序,例如ApiDemos,它显示了一个列表   文本项目。用户可以使用自由地浏览列表   轨迹球,他们也可以使用他们的滚动和推送列表   手指。此方案中的问题是选择。如果我选择一个   列表顶部的项目,然后将列表推向   底部,选择会发生什么?它应该保留在   项目并滚动屏幕?在这种情况下,如果我会发生什么   然后决定用轨迹球移动选择?或者更糟,如果我   按下轨迹球以对当前所选项目进行操作,即   屏幕上没有显示。仔细考虑后,我们决定了   完全删除选择。

     

在触控模式下,没有焦点也没有选择。任何选定的项目   一旦用户输入,就在网格列表中取消选择   触摸模式。同样,任何有焦点的小部件都会变得没有焦点   用户进入触摸模式。下图说明了什么时候会发生什么   用轨迹球选择项目后,用户触摸列表。

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

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

同时设置android:clickable="true"(您也可以设置android:focusable="true"的{​​{1}}。

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

我会尽可能地支持你。

干杯

答案 1 :(得分:0)

我记得滚动视图存在问题,我认为这与您遇到的问题类似。

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

就我而言,我总是从方法中返回true。这告诉来电者您已经处理了焦点变化,所以它不应该尝试进一步做任何事情。

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

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

答案 2 :(得分:0)

除了自定义方式之外,这个问题没有答案,因为你可能已经做过像改变drawable一样。原因是当你滑动时,焦点转到Horizo​​ntalScroll,你只能专注于一个项目,聚焦多个视图是没有意义的。因此要么实现一个drawable(你似乎已经完成了),要么扩展一个复选框并覆盖它的功能,所以当它被聚焦时,它会被检查并改变外观。

答案 3 :(得分:0)

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