2016-11-29 85 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將抓取到哪個元素。