如何在滚动时更改 ScrollView 内部视图的属性并通过滚动触发?

How to change properties of Views inside ScrollView while scrolling and triggered by scrolling?

我在我的应用程序中使用自定义贴靠 ScrollView。它扩展了 Horizo​​ntalScrollView 并覆盖了 onTouchEvent()。这用于在 ScrollView 中间捕捉子视图。还有一个前导和尾随 space,它们足够宽,因此第一个和最后一个元素可以放在中间。
我使用两个 class 变量:

int mActiveFeature //Position of the element nearest to the middle, initially set to 1
List<Integer> mAvailableItems //IDs of contained menu elements in order without the spaces

这是我的 onTouchEvent:

@Override
public boolean onTouchEvent(MotionEvent event) {
    final int menuItemCount = this.mAvailableItems.size();
    switch(event.getAction()) {
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            float scrollX = getScrollX();
            float layoutWidth =
                    SnappingScroll.this.getWidth();
            float featureWidth =
                    (int) getResources().getDimension(R.dimen.item_width);
            float spaceWidth =
                    (int) getResources().getDimension(R.dimen.space_width);

            View oldItem =
                    findViewById(
                            SnappingScroll.this.mAvailableItems.get(
                                    SnappingScroll.this.mActiveFeature - 1
                            )
                    );
            oldItem.setAlpha(0.5f);
            oldItem.setClickable(false);

            SnappingScroll.this.mActiveFeature = (int) Math.min(
                    Math.round((scrollX - spaceWidth + (layoutWidth / 2) + (featureWidth / 2)) / featureWidth),
                    (float) menuItemCount
            );

            View newItem =
                    findViewById(
                            SnappingScroll.this.mAvailableItems.get(
                                    SnappingScroll.this.mActiveFeature - 1
                            )
                    );
            newItem.setAlpha(1.0f);
            newItem.setClickable(true);

            int scrollTo = (int) (
                    SnappingScroll.this.mActiveFeature * featureWidth
                            + spaceWidth
                            - layoutWidth / 2
                            - featureWidth / 2
            );
            smoothScrollTo(scrollTo, 0);
            return true;
        default:
            return super.onTouchEvent(event);
    }

}

这是我正在使用的 XML 文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:orientation="vertical">
    <com.example.SnappingScroll
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center_vertical">
            <Space
                android:id="@+id/leading_space"
                android:layout_width="@dimen/space_width"
                android:layout_height="match_parent" />
            <ImageView
                    android:id="@+id/item_1"
                    android:layout_width="@dimen/item_width"
                    android:layout_height="match_parent"
                    android:alpha="0.5"
                    android:clickable="false"
                    android:onClick="clickFunction"
                    android:src="@drawable/m_1"/>
            <ImageView
                    android:id="@+id/item_2"
                    android:layout_width="@dimen/item_width"
                    android:layout_height="match_parent"
                    android:alpha="0.5"
                    android:clickable="false"
                    android:onClick="clickFunction"
                    android:src="@drawable/m_2"/>
            <ImageView
                    android:id="@+id/item_3"
                    android:layout_width="@dimen/item_width"
                    android:layout_height="match_parent"
                    android:alpha="0.5"
                    android:clickable="false"
                    android:onClick="clickFunction"
                    android:src="@drawable/m_3"/>
            <Space
                android:id="@+id/trailing_space"
                android:layout_width="@dimen/space_width"
                android:layout_height="match_parent" />
        </LinearLayout>
    </com.example.SnappingScroll>
</LinearLayout>

我希望所有元素都半透明且不可点击,活动功能除外。目前,您可以滚动,当您松开时,视图会捕捉到最近的元素。那么最后吸附到的元素是deactivated,新吸附到的元素是activated。这工作正常,但我希望用户在抬起手指时看到 ScrollView 将吸附到哪个元素。因此,新活动特征的计算和透明度的改变应该在滚动时完成。这可能吗?我已经尝试将代码放在 MotionEvent.ACTION_MOVE 的案例中,但是视图根本没有滚动。当我将代码放入 MotionEvent.ACTION_SCROLL 的案例中时,没有任何反应,也没有触发捕捉。


编辑:
起初,我把代码放在一个额外的OnTouchListener中,这是多余的,所以现在我覆盖了onTouchEvent函数并相应地编辑了问题。

经过进一步阅读和一些尝试与错误后,我想出了解决方案。
所以首先,需要的MotionEvent是ACTION_MOVE。我以前试过这个,但没用,因为我自己 returned truefalse,从不调用超类的实现。所以我总是 return super.onTouchEvent(event),因为它处理滚动本身。
只有我的 ACTION_UPACTION_CANCEL 处理没有调用超类,因为这会进行正常滚动并且不会啪啪啪。

@Override
public boolean onTouchEvent(MotionEvent event) {
    final int menuItemCount = this.mAvailableItems.size();

    int oldFeature = this.mActiveFeature;
    float scrollX = getScrollX();
    float layoutWidth =
            SnappingScroll.this.getWidth();
    float featureWidth =
            (int) getResources().getDimension(R.dimen.item_width);
    float spaceWidth =
            (int) getResources().getDimension(R.dimen.space_width);
    View newItem, oldItem;

    switch(event.getAction()) {
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            newItem =
                    findViewById(
                            SnappingScroll.this.mAvailableItems.get(
                                    SnappingScroll.this.mActiveFeature - 1
                            )
                    );
            newItem.setClickable(true);

            int scrollTo = (int) (
                    SnappingScroll.this.mActiveFeature * featureWidth
                            + spaceWidth
                            - layoutWidth / 2
                            - featureWidth / 2
            );
            smoothScrollTo(scrollTo, 0);
            return true;
        case MotionEvent.ACTION_MOVE:
            SnappingScroll.this.mActiveFeature = (int) Math.min(
                    Math.round((scrollX - spaceWidth + (layoutWidth / 2) + (featureWidth / 2)) / featureWidth),
                    (float) menuItemCount
            );

            if(oldFeature == this.mActiveFeature) {
                return super.onTouchEvent(event);
            } else {
                oldItem =
                        findViewById(
                                SnappingScroll.this.mAvailableItems.get(
                                        oldFeature - 1
                                )
                        );
                oldItem.setAlpha(0.5f);
                oldItem.setClickable(false);

                newItem =
                        findViewById(
                                SnappingScroll.this.mAvailableItems.get(
                                        SnappingScroll.this.mActiveFeature - 1
                                )
                        );
                newItem.setAlpha(1.0f);
                return super.onTouchEvent(event);
            }
        default:
            return super.onTouchEvent(event);
    }

}

然后还有最后一个问题要解决。 ScrollView 可以翻转,因此当您抬起手指时,滚动不会停止。这干扰了捕捉,所以我覆盖了 fling() 方法:

@Override
public void fling (int velocityY)
{
    super.fling(0);
}

现在,没有闪动,ScrollView 吸附到最中间的元素。透明度值是在滚动时设置的,因此用户始终知道 ScrollView 将吸附到哪个元素。