2016-11-29 40 views
0

我在我的应用程序中使用自定义捕捉ScrollView。它扩展了Horizo​​ntalScrollView并重写onTouchEvent()。这用于捕捉ScrollView中间的子视图。还有一个领先和尾随空间足够宽,所以第一个和最后一个元素可以放在中间。
我用两个类变量:如何在滚动时通过滚动来更改ScrollView内部的Views属性?

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

的XML文件,我想在半透明度的所有元素除了活动功能外,不可点击。此刻,您可以滚动,并且随着松动,视图捕捉到最近的元素。然后最后一个捕捉到的元素是已停用并且新捕捉到的元素是已激活。这工作正常,但我希望用户看到,当他举起手指时,ScrollView将捕捉哪个元素。因此,新滚动功能的计算和透明度的变化应该在滚动时完成。这可能吗?我已经尝试将代码置于MotionEvent.ACTION_MOVE的情况下,但随后View完全不滚动。当我将代码放入MotionEvent.ACTION_SCROLL的情况下,没有发生任何事情,并且没有触发捕捉。


编辑:
首先,我把代码中的附加OnTouchListener,这是多余的,所以现在我重写的onTouchEvent功能并相应编辑的问题。

回答

0

经过一些进一步的阅读和一些尝试&错误,我想出了解决方案。
首先,所需的MotionEvent是ACTION_MOVE。我之前尝试过,但它没有奏效,因为我自己返回truefalse从未调用超类的实现。所以我总是返回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可以倾斜,因此当你抬起手指时,滚动不会停止。这interferred与捕捉,所以我overrid的一扔()方法

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

现在,没有投掷和滚动型snapps最中间的元素。透明度值是在滚动时设置的,所以用户总是知道ScrollView将抓取到哪个元素。