解决ViewFlipper与ScrollView滑动响应事件拦截的问题

最近在做一个简单的展示界面时,遇到了一个比较棘手的问题。由于要展示多项内容,所以使用ViewFlipper作为水平滑动容器;而每项内容中由于许多文本较长,因此需要使用ScrollView作为垂直滑动容器。基本的界面布局大致如下:

外部文件common_list_view.xml:

Xml代码   收藏代码
  1. <?xml version=”1.0″ encoding=”utf-8″?>
  2. <RelativeLayout
  3. xmlns:android=”http://schemas.android.com/apk/res/android”
  4. android:id=”@+id/geyan_query_view_layout”
  5. android:layout_width=”fill_parent”
  6. android:layout_height=”fill_parent”
  7. android:orientation=”vertical”
  8. android:background=”@drawable/mid_bg”>
  9. <LinearLayout
  10. android:layout_width=”fill_parent”
  11. android:layout_height=”fill_parent”
  12. android:layout_marginTop=”43dip”
  13. android:orientation=”vertical”
  14. android:gravity=”top”
  15. android:layout_gravity=”top”>
  16. <Gallery
  17. android:id=”@+id/gallery_data”
  18. android:layout_width=”fill_parent”
  19. android:layout_height=”fill_parent”
  20. android:gravity=”top”
  21. android:layout_gravity=”top”
  22. android:spacing=”60dip”
  23. android:paddingLeft=”6dip”
  24. android:paddingRight=”6dip”
  25. >
  26. </Gallery>
  27. </LinearLayout>
  28. <ImageView
  29. android:id=”@+id/main_background”
  30. android:layout_width=”fill_parent”
  31. android:layout_height=”fill_parent”/>
  32. <include layout=”@layout/common_title_view”
  33. android:id=”@+id/title”/>
  34. </RelativeLayout>

内部文件common_info_view.xml:

Xml代码   收藏代码
  1. <?xml version=”1.0″ encoding=”utf-8″?>
  2. <LinearLayout
  3. xmlns:android=”http://schemas.android.com/apk/res/android”
  4. android:layout_width=”fill_parent”
  5. android:layout_height=”fill_parent”
  6. android:orientation=”vertical”
  7. android:id=”@+id/linear”>
  8. <TextView
  9. android:id=”@+id/text_title”
  10. android:layout_width=”fill_parent”
  11. android:layout_height=”wrap_content”
  12. android:padding=”5dip”
  13. android:layout_marginTop=”5dip”
  14. android:gravity=”center”
  15. android:textSize=”20sp”
  16. android:textStyle=”bold”
  17. android:textColor=”#181712″
  18. />
  19. <ScrollView
  20. android:id=”@+id/scroll”
  21. android:layout_width=”fill_parent”
  22. android:layout_height=”fill_parent”
  23. android:layout_marginBottom=”5dip”
  24. android:fadeScrollbars=”true”
  25. >
  26. <TextView
  27. android:id=”@+id/text_detail”
  28. android:layout_width=”fill_parent”
  29. android:layout_height=”wrap_content”
  30. android:lineSpacingMultiplier=”1.3″
  31. android:textSize=”18sp”
  32. android:textColor=”#181712″
  33. android:singleLine=”false”
  34. />
  35. </ScrollView>
  36. </LinearLayout>

由于ViewFlipper在外,ScrollView在内,因此一般的做法是定义一个手势响应类来处理响应事件,并将响应事件的处理交给内层的ScrollView。大致代码如下:

Java代码   收藏代码
  1. import android.app.Activity;
  2. import android.os.Bundle;
  3. import android.util.Log;
  4. import android.view.GestureDetector;
  5. import android.view.GestureDetector.SimpleOnGestureListener;
  6. import android.view.LayoutInflater;
  7. import android.view.Menu;
  8. import android.view.MotionEvent;
  9. import android.view.View;
  10. import android.view.Window;
  11. import android.widget.TextView;
  12. import android.widget.Toast;
  13. import android.widget.ViewFlipper;
  14. public class Test1 extends Activity {
  15.     private ViewFlipper viewFlipper;
  16.     private String[] descriptionsArray;
  17.     private String[] titleArray;
  18.     private int selectedPosition;
  19.     private TextView textViewTitle;
  20.     private TextView textViewContent;
  21.     private FriendlyScrollView scroll;
  22.     private LayoutInflater mInflater;
  23.     private GestureDetector gestureDetector;
  24.     @Override
  25.     protected void onCreate(Bundle savedInstanceState) {
  26.         // TODO Auto-generated method stub
  27.         requestWindowFeature(Window.FEATURE_NO_TITLE);
  28.         setContentView(R.layout.common_info_list_view);
  29.         InitUI();
  30.         super.onCreate(savedInstanceState);
  31.         Toast.makeText(this, R.string.hello, Toast.LENGTH_SHORT).show();
  32.     }
  33.     @Override
  34.     public boolean onCreateOptionsMenu(Menu menu) {
  35.         // TODO Auto-generated method stub
  36.         super.onCreateOptionsMenu(menu);
  37.         return false;
  38.     }
  39.     @Override
  40.     public void onBackPressed() {
  41.         // TODO Auto-generated method stub
  42.         finish();
  43.     }
  44.     private void InitUI(){
  45.         viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper_data);
  46.         mInflater = LayoutInflater.from(this);
  47.         fillDate();
  48.         viewFlipper.addView(getContentView());
  49.     }
  50.     private void fillDate(){
  51.         selectedPosition = 0;
  52.         titleArray = getResources().getStringArray(R.array.title_array);
  53.         descriptionsArray = getResources().getStringArray(R.array.description_array);
  54.         gestureDetector = new GestureDetector(new CommonGestureListener());
  55.     }
  56.     private View getContentView() {
  57.         View contentView = new View(this);
  58.         contentView = mInflater.inflate(R.layout.common_info_item_view, null);
  59.         textViewTitle = (TextView) contentView.findViewById(R.id.text_title);
  60.         textViewContent = (TextView) contentView.findViewById(R.id.text_detail);
  61.         textViewTitle.setText(titleArray[selectedPosition]);
  62.         textViewTitle.setPadding(10, 0, 10, 0);
  63.         textViewContent.setText(descriptionsArray[selectedPosition]);
  64.         textViewContent.setPadding(10, 5, 10, 5);
  65.         scroll = (FriendlyScrollView) contentView.findViewById(R.id.scroll);
  66.         scroll.setOnTouchListener(onTouchListener);
  67.         scroll.setGestureDetector(gestureDetector);
  68.         return contentView;
  69.     }
  70.     private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
  71.         public boolean onTouch(View v, MotionEvent event) {
  72.             // TODO Auto-generated method stub
  73.             return gestureDetector.onTouchEvent(event);
  74.         }
  75.     };
  76.     public class CommonGestureListener extends SimpleOnGestureListener {
  77.         @Override
  78.         public boolean onDown(MotionEvent e) {
  79.             // TODO Auto-generated method stub
  80.             Log.d(“QueryViewFlipper”, ”====> Jieqi: do onDown…”);
  81.             return false;
  82.         }
  83.         @Override
  84.         public void onShowPress(MotionEvent e) {
  85.             // TODO Auto-generated method stub
  86.             Log.d(“QueryViewFlipper”, ”====> Jieqi: do onShowPress…”);
  87.             super.onShowPress(e);
  88.         }
  89.         @Override
  90.         public void onLongPress(MotionEvent e) {
  91.             // TODO Auto-generated method stub
  92.             Log.d(“QueryViewFlipper”, ”—-> Jieqi: do onLongPress…”);
  93.         }
  94.         @Override
  95.         public boolean onSingleTapConfirmed(MotionEvent e) {
  96.             // TODO Auto-generated method stub
  97.             Log.d(“QueryViewFlipper”, ”====> Jieqi: do onSingleTapConfirmed…”);
  98.             return false;
  99.         }
  100.         @Override
  101.         public boolean onSingleTapUp(MotionEvent e) {
  102.             // TODO Auto-generated method stub
  103.             Log.d(“QueryViewFlipper”, ”====> Jieqi: do onSingleTapUp…”);
  104.             return false;
  105.         }
  106.         @Override
  107.         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
  108.                 float velocityY){
  109.             // TODO Auto-generated method stub
  110.             Log.d(“QueryViewFlipper”, ”====> Jieqi: do onFling…”);
  111.             if (e1.getX() - e2.getX() > 100 &amp;&amp; Math.abs(velocityX) > 50) {
  112.                 //向左
  113.                 selectedPosition = selectedPosition + 1 < titleArray.length ? (selectedPosition + 1) : 0;
  114.                 viewFlipper.addView(getContentView());
  115.                 viewFlipper.setInAnimation(AnimationControl.inFromRightAnimation());
  116.                 viewFlipper.setOutAnimation(AnimationControl.outToLeftAnimation());
  117.                 viewFlipper.showNext();
  118.                 viewFlipper.removeViewAt(0);
  119.             } else if (e2.getX() - e1.getX() > 100 &amp;&amp; Math.abs(velocityX) > 50) {
  120.                 //向右
  121.                 selectedPosition = selectedPosition > 0 ? (selectedPosition - 1) : (titleArray.length - 1);
  122.                 viewFlipper.addView(getContentView());
  123.                 viewFlipper.setInAnimation(AnimationControl.inFromLeftAnimation());
  124.                 viewFlipper.setOutAnimation(AnimationControl.outToRightAnimation());
  125.                 viewFlipper.showNext();
  126.                 viewFlipper.removeViewAt(0);
  127.             }
  128.             return true;
  129.         }
  130.         @Override
  131.         public boolean onScroll(MotionEvent e1, MotionEvent e2,
  132.                 float distanceX, float distanceY) {
  133.             // TODO Auto-generated method stub
  134.             Log.d(“QueryViewFlipper”, ”====> Jieqi: do onScroll…”);
  135.             return super.onScroll(e1, e2, distanceX, distanceY);
  136.         }
  137.     }
  138. }

这个时候问题出现了,通过Log显示,当ScrollView中内容太短的时候,ScrollView不会触发OnScroll和OnFling事件,导致ViewFlipper左右滑动不响应。(当然后来的另一个测试表明这个问题在ListView上不存在)

为了解决这一个问题,我重新自定义了一个FriendlyScrollView类,来重写ScrollView的onTouchEvent和dispatchTouchEvent方法,具体如下:

Java代码   收藏代码
  1. import android.content.Context;
  2. import android.util.AttributeSet;
  3. import android.view.GestureDetector;
  4. import android.view.MotionEvent;
  5. import android.widget.ScrollView;
  6. public class FriendlyScrollView extends ScrollView {
  7.     GestureDetector gestureDetector;
  8.     public FriendlyScrollView(Context context) {
  9.         super(context);
  10.         // TODO Auto-generated constructor stub
  11.     }
  12.     public FriendlyScrollView(Context context, AttributeSet attrs) {
  13.         super(context, attrs);
  14.         // TODO Auto-generated constructor stub
  15.     }
  16.     public FriendlyScrollView(Context context, AttributeSet attrs, int defStyle) {
  17.         super(context, attrs, defStyle);
  18.         // TODO Auto-generated constructor stub
  19.     }
  20.     public void setGestureDetector(GestureDetector gestureDetector) {
  21.         this.gestureDetector = gestureDetector;
  22.     }
  23.     @Override
  24.     public boolean onTouchEvent(MotionEvent event) {
  25.         super.onTouchEvent(event);
  26.         return gestureDetector.onTouchEvent(event);
  27.     }
  28.     @Override
  29.     public boolean dispatchTouchEvent(MotionEvent ev){
  30.         gestureDetector.onTouchEvent(ev);
  31.         super.dispatchTouchEvent(ev);
  32.         return true;
  33.     }
  34. }

然后将common_info_view.xml和程序中的ScrollView改成FriendlyScrollView,终于解决了这个问题。

你可能感兴趣的:(解决ViewFlipper与ScrollView滑动响应事件拦截的问题)