我正在使用我的应用程序中的自定义Snapping scollview。它扩展了HorizontalScrollview并覆盖OnTouchEvent()。这用于在卷轴中间拍摄孩子的视图。还有一个足够宽的领先空间和尾随空间,因此可以将第一个和最后一个元素放在中间。
我使用两个类变量:
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>
我希望所有元素以一半透明,而不是可单击的,除了活动功能。目前,您可以滚动,然后放开时,视图捕捉到最近的元素。然后,最后一个被捕获到元素的停用,而新的元素被激活为。这很好,但是我希望用户看到,当他抬起手指时,Scrollview会捕捉到哪个元素。因此,应在滚动时完成新的活动功能的计算和更改透明度。这可能吗?我已经尝试将代码放在for MotionEvent.action_move的情况下,但是随后该视图根本没有滚动。当我将代码放入MotionEvent.action_scroll的情况下时,什么也没有发生,并且没有触发捕捉。
编辑:
首先,我将代码放入额外的OnTouchListener中,该代码是多余的,因此现在我覆盖了OnTouchEvent函数并相应地编辑了该问题。
在进行进一步的阅读和一些尝试之后错误,我想出了解决方案。
因此,首先,所需的MotionEvent是 Action_Move 。我以前尝试过,但是它没有起作用,因为我自己返回了 true 和 false ,从不调用超级类的实现。因此,我总是返回 super.ontouchevent(event),因为这可以处理滚动本身。
只有我的 action_up 和 action_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);
}
}
那么解决了最后一个问题。滚动浏览可以逃跑,因此抬起手指时,滚动不会停止。这会干扰扣子,所以我覆盖了 fling()方法:
@Override
public void fling (int velocityY)
{
super.fling(0);
}
现在,没有fling弹,滚动浏览snapps到最中间的元素上。滚动时设置了透明度值,因此用户始终知道,滚动视图将符合哪个元素。