ScrollViewsを含むViewFlipperでレイアウトを作成しようとしています。アイデアは、水平スワイプを検出して前/次のScrollViewに移動することです。さらに、ScrollViewには、前/次のImageViewに移動する垂直スワイプ検出器を備えたImageViewを含む別のViewFlipperが含まれています。 ScrollViewをLinearLayoutに置き換えると、両方のジェスチャー検出器は適切に機能しますが、ScrollViewでは機能しません(ジェスチャーリスナーはトリガーさえもしません)。 ScrollViewを使用するとジェスチャー検出器が無効になるのはなぜですか?どうすれば機能させることができますか?
アクティビティ
public class ProduitHome extends Activity{
private Resources res;
float density;
private int position, parent_id;;
private int num_products;
private Produit produit;
private ImageDownloader mImageLoader;
private ViewFlipper product_viewflipper;
private ScrollView current_product_layout;
Animation next_product_out, next_product_in, previous_product_in, previous_product_out;
private GestureDetector galleryGestureDetector;
private View.OnTouchListener galleryGestureListener;
private GestureDetector productGestureDetector;
private View.OnTouchListener productGestureListener;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.produit_home);
num_products = GlobalData.map_list_produits.get(parent_id).size();
product_viewflipper = (ViewFlipper) findViewById(R.id.product_viewflipper);
LayoutInflater inflater = getLayoutInflater();
// Add num_products view to the viewflipper
for(int i=0; i<num_products; i++){
ScrollView product_detail = (ScrollView) inflater.inflate(R.layout.produit_detail, null);
product_viewflipper.addView(product_detail);
}
// Set data and show current product
current_product_layout = (ScrollView) product_viewflipper.getChildAt(position);
product_viewflipper.setDisplayedChild(position);
setProductData();
// Set swipe listener to switch product
productGestureDetector = new GestureDetector(new ProductGestureListener());
productGestureListener = new View.OnTouchListener()
{
public boolean onTouch(View v, MotionEvent event)
{
if (productGestureDetector.onTouchEvent(event))
{
return true;
}
else{
return false;
}
}
};
product_viewflipper.setOnTouchListener(productGestureListener);
// Set switch product animation
next_product_out = AnimationUtils.loadAnimation(this, R.anim.next_product_out);
next_product_in = AnimationUtils.loadAnimation(this, R.anim.next_product_in);
previous_product_in = AnimationUtils.loadAnimation(this, R.anim.previous_product_in);
previous_product_out = AnimationUtils.loadAnimation(this, R.anim.previous_product_out);
}
class VerticalSwipeListener extends SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
final int SWIPE_MIN_DISTANCE = 80;
final int SWIPE_MAX_OFF_PATH = 250;
final int SWIPE_THRESHOLD_VELOCITY = 200;
try {
if (Math.abs(e1.getX() - e2.getX()) > SWIPE_MAX_OFF_PATH)
return false;
ViewFlipper gallery = (ViewFlipper)current_product_layout.findViewById(R.id.product_gallery);
if(e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
gallery.showNext();
} else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
gallery.showPrevious();
}
((RadioGroup)current_product_layout.findViewById(R.id.gallery_nav)).check(gallery.getDisplayedChild());
} catch (Exception e) {
}
return false;
}
}
class ProductGestureListener extends SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
final int SWIPE_MIN_DISTANCE = 120;
final int SWIPE_MAX_OFF_PATH = 250;
final int SWIPE_THRESHOLD_VELOCITY = 200;
if(!Utils.IsOnline(ProduitHome.this)){
SRPDialogs.show(ProduitHome.this, SRPDialogs.NOT_CONNECTED);
}
else{
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
if(e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
// show next product
} else if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
// show previous product
}
} catch (Exception e) {
}
}
return false;
}
}
public void setProductData(){
produit = GlobalData.map_produits.get(GlobalData.map_list_produits.get(parent_id).get(position).id);
TextView name = (TextView) current_product_layout.findViewById(R.id.name);
name.setText(produit.libelle);
// Load gallery
int nPics = produit.list_url_pic.size();
if(nPics>0){
ViewFlipper gallery = (ViewFlipper) current_product_layout.findViewById(R.id.product_gallery);
gallery.removeAllViews();
mImageLoader = new ImageDownloader(res,
((BitmapDrawable)res.getDrawable(R.drawable.default_row_pic)).getBitmap(), 1);
final ViewFlipper.LayoutParams params_vf = new ViewFlipper.LayoutParams(ViewFlipper.LayoutParams.FILL_PARENT, ViewFlipper.LayoutParams.FILL_PARENT);
for(String url : produit.list_url_pic){
// Add images to viewflipper
ImageView imageView_p = new ImageView(this);
imageView_p.setLayoutParams(params_vf);
imageView_p.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView_p.setTag(url);
imageView_p.setImageResource(R.drawable.default_row_pic);
mImageLoader.download(url, imageView_p);
gallery.addView(imageView_p);
}
// Swipe detector to switch picture in gallery
galleryGestureDetector = new GestureDetector(new VerticalSwipeListener());
galleryGestureListener = new View.OnTouchListener()
{
public boolean onTouch(View v, MotionEvent event)
{
if (galleryGestureDetector.onTouchEvent(event))
{
return true;
}
else{
return false;
}
}
};
}
}
}
親のレイアウト
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/product_home" Android:layout_width="fill_parent"
Android:layout_height="fill_parent" Android:orientation="vertical"
Android:background="@color/grey_bg">
<!-- more stuff -->
<ViewFlipper Android:id="@+id/product_viewflipper"
Android:layout_width="fill_parent" Android:layout_height="fill_parent"
Android:layout_below="@id/header_logo" />
<!-- more stuff -->
</RelativeLayout>
ViewFlipperの子のレイアウト
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="fill_parent" Android:layout_height="fill_parent"
Android:background="@color/grey_bg">
<LinearLayout Android:layout_width="fill_parent"
Android:layout_height="wrap_content" Android:orientation="vertical"
Android:gravity="center_horizontal">
<!-- more stuff -->
<RelativeLayout Android:layout_below="@id/bg_content_top"
Android:layout_above="@id/bg_content_bottom"
Android:layout_width="300dp" Android:layout_height="fill_parent"
Android:background="@drawable/bg_content"
Android:paddingRight="3dp" Android:paddingLeft="3dp"
Android:layout_centerHorizontal="true">
<!-- more stuff -->
<RelativeLayout Android:id="@+id/content"
Android:layout_below="@id/title_container"
Android:layout_above="@id/bg_content_bottom"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:paddingLeft="7dp" Android:paddingRight="7dp"
Android:paddingTop="10dp" Android:paddingBottom="10dp">
<ViewFlipper Android:id="@+id/product_gallery"
Android:clickable="true" Android:focusable="false"
Android:layout_width="100dp" Android:layout_height="150dp"
Android:layout_marginRight="10dp"
Android:layout_below="@id/title_container"
Android:layout_toRightOf="@id/gallery_nav" />
<!-- more stuff -->
</RelativeLayout>
</RelativeLayout>
<!-- more stuff -->
</LinearLayout>
</ScrollView>
追加しなければならなかった
@Override
public boolean dispatchTouchEvent(MotionEvent ev){
super.dispatchTouchEvent(ev);
return productGestureDetector.onTouchEvent(ev);
}
私の活動で。
私の答えは、より明確にすることを除いて、私の最後の答えと同じです。
変化する
<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="fill_parent" Android:layout_height="fill_parent"
Android:background="@color/grey_bg">
に
<your.packagename.CustomScrollView ... etc>
クラスを作成する
public class CustomScrollView extends ScrollView {
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
gestureDetector = new GestureDetector(new YScrollDetector());
setFadingEdgeLength(0);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//Call super first because it does some hidden motion event handling
boolean result = super.onInterceptTouchEvent(ev);
//Now see if we are scrolling vertically with the custom gesture detector
if (gestureDetector.onTouchEvent(ev)) {
return result;
}
//If not scrolling vertically (more y than x), don't Hijack the event.
else {
return false;
}
}
// Return false if we're scrolling in the x direction
class YScrollDetector extends SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
try {
if (Math.abs(distanceY) > Math.abs(distanceX)) {
return true;
} else {
return false;
}
} catch (Exception e) {
// nothing
}
return false;
}
}
そのコードは、ここのトップの回答から得られます: ScrollViewタッチ処理内のHorizontalScrollView (答えが役に立つ場合は投票してください)。
垂直方向を取得したい場合は、変更します
if (Math.abs(distanceY) > Math.abs(distanceX)) {
に
if (Math.abs(distanceY) < Math.abs(distanceX)) {
CustomScrollView
は、上記の2行のコードに応じて、水平または垂直に1つの軸のスワイプのみをインターセプトします。 1つの軸のスワイプのみをインターセプトするため、残りのイベントはその子に渡されるため、アクティビティのジェスチャー/タッチリスナーでイベントを処理できます。
また、すべての参照/キャストをScrollView
から新しいカスタムのもの(CustomScrollView
)に変更する必要があります。
parentScrollView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return productGestureDetector.onTouchEvent(event);
}
});
メインのスクロールビューをTouchListenerに設定し、このコードを実装します。お役に立てれば幸いです。