![](/img/trans.png)
[英]How can I set view pager's on Item Click Listener? Set On Click Listener is not working
[英]How can I detect a click in an onTouch listener?
我在ScrollView
有一個ViewPager
。 我需要能夠水平和垂直滾動。 為了實現這一點,必須在我的ViewPager
被觸摸時禁用垂直滾動( v.getParent().requestDisallowInterceptTouchEvent(true);
),以便它可以水平滾動。
但同時我需要能夠單擊 viewPager 以全屏模式打開它。
問題是 onTouch 在 onClick 之前被調用,而我的 OnClick 從未被調用。
如何在觸摸時同時實現 onClick?
viewPager.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("TOUCHED ");
if(event.getAction() == MotionEvent.???){
//open fullscreen activity
}
v.getParent().requestDisallowInterceptTouchEvent(true); //This cannot be removed
return false;
}
});
viewPager.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("CLICKED ");
Intent fullPhotoIntent = new Intent(context, FullPhotoActivity.class);
fullPhotoIntent.putStringArrayListExtra("imageUrls", imageUrls);
startActivity(fullPhotoIntent);
}
});
Masoud Dadashi 的回答幫助我弄清楚了。
這就是它最終的樣子。
viewPager.setOnTouchListener(new OnTouchListener() {
private int CLICK_ACTION_THRESHOLD = 200;
private float startX;
private float startY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_UP:
float endX = event.getX();
float endY = event.getY();
if (isAClick(startX, endX, startY, endY)) {
launchFullPhotoActivity(imageUrls);// WE HAVE A CLICK!!
}
break;
}
v.getParent().requestDisallowInterceptTouchEvent(true); //specific to my project
return false; //specific to my project
}
private boolean isAClick(float startX, float endX, float startY, float endY) {
float differenceX = Math.abs(startX - endX);
float differenceY = Math.abs(startY - endY);
return !(differenceX > CLICK_ACTION_THRESHOLD/* =5 */ || differenceY > CLICK_ACTION_THRESHOLD);
}
}
通過檢查用戶觸摸屏幕的時間,我做了一些非常簡單的事情。
private static int CLICK_THRESHOLD = 100;
@Override
public boolean onTouch(View v, MotionEvent event) {
long duration = event.getEventTime() - event.getDownTime();
if (event.getAction() == MotionEvent.ACTION_UP && duration < CLICK_THRESHOLD) {
Log.w("bla", "you clicked!");
}
return false;
}
另外值得注意的是, GestureDetector內置了類似的東西。 看看 onSingleTapUp
兩者都發展是錯誤的想法。 當用戶可以通過觸摸屏幕來做不同的事情時,理解用戶目的有點漂亮,你需要為它開發一段代碼。
兩種解決方案:
1-(更好的主意)在您的 onTouch 事件中檢查是否有動作。 您可以通過檢查是否有任何移動來做到這一點:
ACTION_UP
ACTION_DOWN
ACTION_MOVE
像這樣做
if(event.getAction() != MotionEvent.ACTION_MOVE)
您甚至可以檢查用戶手指在屏幕上的移動距離,以確保發生了移動,而不是點擊時的意外移動。 像這樣做:
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
if(isDown == false)
{
startX = event.getX();
startY = event.getY();
isDown = true;
}
Break;
case MotionEvent.ACTION_UP
{
endX = event.getX();
endY = event.getY();
break;
}
}
如果上述情況均未發生,則將其視為一次單擊,並通過單擊執行您想做的事情。
2)如果你的 UI 有問題,創建一個按鈕或圖像按鈕或任何用於全屏的東西,並為它設置一個 onClick。
祝你好運
您可能需要區分用戶單擊和長按。 否則,您會將兩者檢測為同一事物。 我這樣做是為了使它成為可能:
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
bClick = true;
tmrClick = new Timer();
tmrClick.schedule(new TimerTask() {
public void run() {
if (bClick == true) {
bClick = false;
Log.d(LOG_TAG, "Hey, a long press event!");
//Handle the longpress event.
}
}
}, 500); //500ms is the standard longpress response time. Adjust as you see fit.
return true;
case MotionEvent.ACTION_UP:
endX = event.getX();
endY = event.getY();
diffX = Math.abs(startX - endX);
diffY = Math.abs(startY - endY);
if (diffX <= 5 && diffY <= 5 && bClick == true) {
Log.d(LOG_TAG, "A click event!");
bClick = false;
}
return true;
default:
return false;
}
}
不要試圖重新發明輪子!
優雅的方法:
public class CustomView extends View {
private GestureDetectorCompat mDetector;
public CustomView(Context context) {
super(context);
mDetector = new GestureDetectorCompat(context, new MyGestureListener());
}
@Override
public boolean onTouchEvent(MotionEvent event){
return this.mDetector.onTouchEvent(event);
}
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {return true;}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
//...... click detected !
return false;
}
}
}
上面的答案主要是記住時間。 但是, MotionEvent
已經涵蓋了您。 這是一個開銷較小的解決方案。 它是用kotlin
寫的,但應該還是可以理解的:
private const val ClickThreshold = 100
override fun onTouch(v: View, event: MotionEvent): Boolean {
if(event.action == MotionEvent.ACTION_UP
&& event.eventTime - event.downTime < ClickThreshold) {
v.performClick()
return true // If you don't want to do any more actions
}
// do something in case its not a click
return true // or false, whatever you need here
}
這個解決方案對於大多數應用程序來說已經足夠好了,但在區分點擊和快速滑動方面不太好。
因此,將其與上面的答案結合起來,也考慮到這個位置可能是最好的答案。
我認為組合解決方案時間/位置應該更好:
private float initialTouchX;
private float initialTouchY;
private long lastTouchDown;
private static int CLICK_ACTION_THRESHHOLD = 100;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastTouchDown = System.currentTimeMillis();
//get the touch location
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
return true;
case MotionEvent.ACTION_UP:
int Xdiff = (int) (event.getRawX() - initialTouchX);
int Ydiff = (int) (event.getRawY() - initialTouchY);
if (System.currentTimeMillis() - lastTouchDown < CLICK_ACTION_THRESHHOLD && (Xdiff < 10 && Ydiff < 10)) {
//clicked!!!
}
return true;
}
return false;
}
});
我相信您會阻止您的視圖以這種方式接收觸摸事件,因為您的 TouchListener 會攔截它。 你可以
v.onTouchEvent(event)
在 ToucheListener 中調度事件ViewPager.onTouchEvent(MotionEvent)
不攔截事件此外,返回true
意味着您沒有消費該事件,並且您對后續事件不感興趣,因此在手勢完成之前您不會收到后續事件(即手指再次向上)。
你可以使用 OnTouchClickListener
用法:
view.setOnTouchListener(new OnTouchClickListener(new OnTouchClickListener.OnClickListener() { @Override public void onClick(View v) { //perform onClick } },5));
if (event.eventTime - event.downTime < 100 && event.actionMasked == MotionEvent.ACTION_UP) {
view.performClick()
return false
}
此代碼將執行觸摸事件和單擊事件。
viewPager.setOnTouchListener(new View.OnTouchListener() {
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//remember the initial position.
initialX = params.x;
initialY = params.y;
//get the touch location
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
return true;
case MotionEvent.ACTION_UP:
int Xdiff = (int) (event.getRawX() - initialTouchX);
int Ydiff = (int) (event.getRawY() - initialTouchY);
//The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little while clicking.
if (Xdiff < 10 && Ydiff < 10) {
//So that is click event.
}
return true;
case MotionEvent.ACTION_MOVE:
//Calculate the X and Y coordinates of the view.
params.x = initialX + (int) (event.getRawX() - initialTouchX);
params.y = initialY + (int) (event.getRawY() - initialTouchY);
//Update the layout with new X & Y coordinate
mWindowManager.updateViewLayout(mFloatingView, params);
return true;
}
return false;
}
});
這是來源。
我認為你的問題來自於:
v.getParent().requestDisallowInterceptTouchEvent(true); //This cannot be removed
看看文檔。 你試過刪除線嗎? 不刪除此行的要求是什么?
考慮到,根據文檔,如果您從 onTouchListener 返回 true,則使用該事件,如果您返回 false,則傳播該事件,因此您可以使用它來傳播該事件。
此外,您應該從以下位置更改您的代碼:
System.out.println("CLICKED ");
至:
Log.d("MyApp", "CLICKED ");
在 logcat 中獲得正確的輸出。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.