【问题标题】:Implementing Swipe action on ViewFlipper with multiple GridViews使用多个 GridView 在 ViewFlipper 上实现 Swipe 操作
【发布时间】:2011-03-02 02:14:30
【问题描述】:

我有以下代码来监听 Swipe 操作以在我的 ViewFlipper 中的 GridView 之间导航。但是,它检测到的滑动不一致。我将手势侦听器添加到每个 GridView 以及 GridView 中的每个项目。我还有什么遗漏的吗?

完整代码如下:

public class ListNewsActivity extends Activity implements OnGestureListener {

String TAG = "ListNewsActivity";

private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;

private static final int DIALOG_PLEASE_WAIT = 100;
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;

private Animation slideLeftIn;
private Animation slideLeftOut;
private Animation slideRightIn;
private Animation slideRightOut;

private static int MAX_STREAMS = AppSettings.getStreamList().size();

Context context;

ViewFlipper flipper;

StreamHeader header;

int currentStreamIndex = 0;

ArrayList<StreamNav> navList = new ArrayList<StreamNav>();
ArrayList<StreamGridView> gridList = new ArrayList<StreamGridView>();


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {

    context = getApplicationContext();
    super.onCreate(savedInstanceState);
    setContentView(R.layout.stream);

    if (AppSettings.userToken == null) {
        AppSettings.getUserToken(context);
    }

    header = (StreamHeader) findViewById(R.id.stream_header);
    setHeaderTitle();

    flipper = (ViewFlipper)findViewById(R.id.stream_flipper);

    boolean loadData = false;
    Log.v(TAG, "No. of streams: " + String.valueOf(AppSettings.getStreamList().size()));
    for (Stream stream : AppSettings.getStreamList()) {
        Log.v(TAG, "Checking Stream  " + stream.getName());
        if (stream.getPosts() == null || stream.getPosts().size() == 0) {
            loadData = true;
            Log.v(TAG, "Empty Stream for " + stream.getBlogId() + ". Data will be loaded.");
            break;
        }
        else {
            Log.v(TAG, "Stream " + stream.getName() + " is populated. Posts: " + String.valueOf(stream.getPosts().size()));
        }
    }

    setupNavAndGrids();

    if (loadData) {
        new LoadStreamTask().execute();
    }
    else {
        populateGrids();
    }

    slideLeftIn = AnimationUtils.loadAnimation(this, R.anim.stream_flipper_slidein_from_right);
    slideLeftOut = AnimationUtils.loadAnimation(this, R.anim.stream_flipper_slideout_to_left);
    slideRightIn = AnimationUtils.loadAnimation(this, R.anim.stream_flipper_slidein_from_left);
    slideRightOut = AnimationUtils.loadAnimation(this, R.anim.stream_flipper_slideout_to_right);

    gestureDetector = new GestureDetector(new MyGestureDetector());
    gestureListener = new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {

            if (gestureDetector.onTouchEvent(event)) {
                return true;
            }
            return false;
        }
    };

}

public void setupNavAndGrids() {

    LinearLayout llNav = (LinearLayout) findViewById(R.id.stream_nav_layout);

    View.OnClickListener navOnClickListener = new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            StreamNav nav = (StreamNav)v;
            navigateToStream(nav.getStreamIndex());

        }
    };

    for (int i = 0; i < MAX_STREAMS; i++) {
        StreamNav nav = new StreamNav(context, null);
        nav.setStreamIndex(i);
        nav.setOnClickListener(navOnClickListener);
        navList.add(nav);
        llNav.addView(nav);

        StreamGridView gv = new StreamGridView(context, null);
        gv.setOnTouchListener(gestureListener);
        gridList.add(gv);

        flipper.addView(gv);

    }

    navList.get(0).setSelected(true);

}

void navigateToStream(int newStreamIndex) {

    for (StreamNav nav : navList) {
        if (nav.getStreamIndex() == newStreamIndex) {
            nav.setSelected(true);
        }
        else {
            nav.setSelected(false);
        }
    }
    Log.v(TAG, "Navigate To Stream: currentStreamIndex=" + String.valueOf(currentStreamIndex) + " newStreamIndex " + String.valueOf(newStreamIndex));
    if (currentStreamIndex < newStreamIndex) {
        int ctr = newStreamIndex - currentStreamIndex;
        for (int i = 0; i < ctr; i++) {
            showNext();
        }
    }
    else {
        int ctr =  currentStreamIndex - newStreamIndex;
        for (int i = 0; i < ctr; i++) {
            showPrevious();
        }
    }
}

public void showNext() {
    Toast.makeText(context, "Show Next Page for Flipper", Toast.LENGTH_LONG);
    flipper.setInAnimation(this, R.anim.stream_flipper_slidein_from_right);
    flipper.setOutAnimation(this, R.anim.stream_flipper_slideout_to_left);
    flipper.showNext();
    setStreamIndex(1);
    setHeaderTitle();
    }

public void showPrevious() {
    Toast.makeText(context, "Show Previous Page for Flipper", Toast.LENGTH_LONG);
    flipper.setInAnimation(this, R.anim.stream_flipper_slidein_from_left);
    flipper.setOutAnimation(this, R.anim.stream_flipper_slideout_to_right);
    flipper.showPrevious();
    setStreamIndex(-1);
    setHeaderTitle();
}

void setStreamIndex(int step) {
    if (step == 1) {
        if (currentStreamIndex == MAX_STREAMS) {
            currentStreamIndex = 0;
        }
        else {
            currentStreamIndex++;
        }
    }
    else {
        // -1 which means previous
        if (currentStreamIndex == 0) {
            currentStreamIndex = MAX_STREAMS - 1;
        }
        else {
            currentStreamIndex--;
        }
    }
}

void setHeaderTitle() {
    header.setTitle(AppSettings.getStreamList().get(currentStreamIndex).getName());
}

void populateGrids() {
    int pos = -1;
    for (StreamGridView sgv : gridList) {
        pos++;
        Log.v(TAG, "Loading Stream for " + AppSettings.getStreamList().get(pos).getName() + "; Posts: " + String.valueOf(AppSettings.getStreamList().get(pos).getPosts().size()));
        ArrayList<Post> posts = AppSettings.getStreamList().get(pos).getPosts();
        sgv.adapter = new LazyPostItemAdapter(ListNewsActivity.this, posts, gestureListener);
        sgv.gvStream.setAdapter(sgv.adapter);

    }
}
class LoadStreamTask extends AsyncTask<Void, String, Void> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        showDialog(DIALOG_PLEASE_WAIT);

    }

    @Override
    protected Void doInBackground(Void... unused) {

        for (Stream stream : AppSettings.getStreamList()) {

            if (stream.getBlogId().equalsIgnoreCase("popular")) {
                stream.setPosts(Post.getPopularStream());
            }
            else if (stream.getBlogId().equalsIgnoreCase("recent")) {
                stream.setPosts(Post.getRecentStream());
            }
            else {
                Blog blog = Blog.getBlog(stream.getBlogId());
                stream.setPosts(Post.getPostsForBlog(blog));
            }
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void unused) {

        populateGrids();
        dismissDialog(DIALOG_PLEASE_WAIT);
    }
}

@Override
protected Dialog onCreateDialog(int id) {
    switch (id) {
        case DIALOG_PLEASE_WAIT:
            ProgressDialog mProgressDialog;
            mProgressDialog = new ProgressDialog(this);
            mProgressDialog.setMessage("Loading Streams...");
            mProgressDialog.setCancelable(false);
            mProgressDialog.show();
            return mProgressDialog;
        default:
            return null;
    }
}

class MyGestureDetector extends SimpleOnGestureListener {
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        Log.v(TAG, "onFling");
        try {
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                return false;
            // right to left swipe
            if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                flipper.setInAnimation(slideLeftIn);
                flipper.setOutAnimation(slideLeftOut);
                flipper.showNext();
            }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                flipper.setInAnimation(slideRightIn);
                flipper.setOutAnimation(slideRightOut);
                flipper.showPrevious();
            }
        } catch (Exception e) {
            // nothing
        }
        return false;
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (gestureDetector.onTouchEvent(event))
        return true;
    else
        return false;
}


@Override
public boolean onDown(MotionEvent e) {
    // TODO Auto-generated method stub
    return false;
}


@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
        float velocityY) {
    // TODO Auto-generated method stub
    return false;
}


@Override
public void onLongPress(MotionEvent e) {
    // TODO Auto-generated method stub

}


@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
        float distanceY) {
    // TODO Auto-generated method stub
    return false;
}


@Override
public void onShowPress(MotionEvent e) {
    // TODO Auto-generated method stub

}


@Override
public boolean onSingleTapUp(MotionEvent e) {
    // TODO Auto-generated method stub
    return false;
}

}

【问题讨论】:

    标签: android


    【解决方案1】:

    我一直在 StackOverflow 上看到相同的滑动手势检测代码,因此我尝试对其进行一些清理。这是一个通用的监听器,可以触发左右滑动的事件(很容易扩展到其他

    public class SwipeListener extends GestureDetector.SimpleOnGestureListener {
    
        private static final int SWIPE_MIN_DISTANCE = 120;
        private static final int SWIPE_MAX_OFF_PATH = 250;
        private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    
        private SwipeHandler handler;
    
        public SwipeHandler getHandler() {
            return handler;
        }
    
        public void setHandler(SwipeHandler handler) {
            this.handler = handler;
        }
    
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                return false;
    
            // left
            if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
    
                if (handler != null) {
                    handler.onLeft();
    
                    return true;
                }
    
            // right
            } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
    
                if (handler != null) {
                    handler.onRight();
    
                    return true;
                }
            }
    
            return super.onFling(e1, e2, velocityX, velocityY);
        }
    
        public static abstract class SwipeHandler{
            public void onLeft() {}
            public void onRight() {}
        }
    }
    

    然后要在任何地方使用它,只需创建一个实例,设置您的滑动事件处理程序,然后附加它:

        SwipeListener swipeListener = new SwipeListener();
        swipeListener.setHandler(new SwipeListener.SwipeHandler() {
            @Override
            public void onRight() {
                doSomething();
            }
        });
    
        someView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return gestureDetector.onTouchEvent(event);
            }
        });
    

    【讨论】:

    【解决方案2】:

    我在这里有几个问题/意见:

    问:您能否详细说明不一致的含义?没有检测到滑动时是否有任何模式?它真的有效吗?如果有,什么时候?

    问:在您的主 Activity 中,在重写的 onTouchEvent(MotionEvent me) 方法中,您是否像这样返回 myGestureDetector.onTouchEvent(me)?

    @Override    
    public boolean onTouchEvent(MotionEvent me) {
         return myGestureDetector.onTouchEvent(me);    
    }
    

    这里 myGestureDetector 是您的 MyGestureDetector 类的一个对象,这基本上将您的 GestureDetector 附加到触摸事件

    观察:您能否在手势处理完成后立即返回 true,例如,告诉 android 手势捕获已完成

            if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                flipper.setInAnimation(slideLeftIn);
                flipper.setOutAnimation(slideLeftOut);
                flipper.showNext();
                //return true if the gesture event is consumed
                return true; 
            }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                flipper.setInAnimation(slideRightIn);
                flipper.setOutAnimation(slideRightOut);
                flipper.showPrevious();
                //return true if the gesture event is consumed
                return true;
            }
    

    【讨论】:

    • 有时滑动有效,有时有效。向右滑动时效果更好。我用完整的代码更新了问题。
    【解决方案3】:

    1) 你是否在 viewflipper 中添加了所有的网格视图。

    viewFlipper = (ViewFlipper)findViewById(R.id.flipper);
                slideLeftIn = AnimationUtils.loadAnimation(this, R.anim.slide_left_in);
                slideLeftOut = AnimationUtils.loadAnimation(this, R.anim.slide_left_out);
                slideRightIn = AnimationUtils.loadAnimation(this, R.anim.slide_right_in);
                slideRightOut = AnimationUtils.loadAnimation(this, R.anim.slide_right_out);
    
                gestureDetector = new GestureDetector(new MyGestureDetector());
                gestureListener = new View.OnTouchListener() 
                    {
                        public boolean onTouch(View v, MotionEvent event) 
                        {
                            if (gestureDetector.onTouchEvent(event)) 
                            {
                                    return true;
                            }
                            else{
                                    return false;}
                            }
                    };
    

    我已经在我的代码中添加了这些,它工作正常。只需检查这个让我知道

    【讨论】:

    • 是的,我有这些。对于带有 TextViews 的 ViewFlipper,我有相同的代码。但是,如果我有 GridViews,它就不起作用。你的应用在你的 ViewFlipper 中有 GridViews 吗?
    猜你喜欢
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 2022-12-21
    • 1970-01-01
    • 2019-12-09
    相关资源
    最近更新 更多