Ich habe ein Problem mit der Implementierung von Double Tap. Nun, ich habe onGestureListener
implementiert und hatte gestureDetector
, aber ich bin nicht sicher, wo das Problem liegt. Hier ist mein Code:
public class home extends TabActivity implements OnGestureListener {
/** Called when the activity is first created. */
private EditText queryText;
private ResultsAdapter m_adapter;
private ProgressDialog pd;
final Handler h = new Handler();
private TabHost mTabHost;
private ArrayList<SearchItem> sResultsArr = new ArrayList<SearchItem>();
private String queryStr;
private JSONObject searchResponse;
private GestureDetector gestureScanner;
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateListUi();
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button search = (Button)findViewById(R.id.search);
Button testButt = (Button)findViewById(R.id.testbutt);
queryText = (EditText)findViewById(R.id.query);
ListView lvr = (ListView)findViewById(R.id.search_results);
//initialise the arrayAdapter
this.m_adapter = new ResultsAdapter(home.this, R.layout.listrow, sResultsArr);
lvr.setAdapter(this.m_adapter);
lvr.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
pd = ProgressDialog.show(home.this, null,"Loading products from server", true, false);
}
});
gestureScanner = new GestureDetector(this,this);
gestureScanner.setOnDoubleTapListener(new OnDoubleTapListener(){
public boolean onDoubleTap(MotionEvent e) {
//viewA.setText("-" + "onDoubleTap" + "-");
pd = ProgressDialog.show(home.this, null,"Loading products from server", true, false);
return false;
}
public boolean onDoubleTapEvent(MotionEvent e) {
// viewA.setText("-" + "onDoubleTapEvent" + "-");
return false;
}
public boolean onSingleTapConfirmed(MotionEvent e) {
//viewA.setText("-" + "onSingleTapConfirmed" + "-");
return false;
}
});
//initialise tab contents
mTabHost = getTabHost();
mTabHost.addTab(mTabHost.newTabSpec("tab1").setIndicator("Home").setContent(R.id.homepage));
mTabHost.addTab(mTabHost.newTabSpec("tab2").setIndicator("Search Results").setContent(R.id.tab2));
mTabHost.setCurrentTab(0);
//sets the respective listeners
testButt.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
if(mTabHost.getTabWidget().getVisibility()==View.GONE){
mTabHost.getTabWidget().setVisibility(View.VISIBLE);
}
else{
mTabHost.getTabWidget().setVisibility(View.GONE);
}
}
});
search.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
sResultsArr.clear();
queryStr = "http://rose.mosuma.com/mobile?query=" + queryText.getText().toString();
pd = ProgressDialog.show(home.this, null,"Loading products from server", true, false);
goSearch();
}
});
}
//updates the listUI whenever after receiving the response from the server
public void updateListUi(){
if(sResultsArr.size() > 0){
}
try{
String ptypename;
int count;
LinearLayout ptypebar = (LinearLayout)findViewById(R.id.productCat);
ptypebar.removeAllViews();
JSONArray ptypes = searchResponse.getJSONArray("ptypes");
for(int index =0;index < ptypes.length();index++){
JSONObject ptype = ptypes.getJSONObject(index);
count = ptype.getInt("count");
ptypename = ptype.getString("ptypename");
//add into tab 2's UI
//ImageView icon = new ImageView(this);
TextView t = new TextView(home.this);
t.setText(ptypename + " (" + count + ")");
ptypebar.addView(t);
}
}
catch(JSONException e){
}
//if(m_adapter.getItems() != sResultsArr){
ArrayList<SearchItem> a = m_adapter.getItems();
a = sResultsArr;
//}
m_adapter.notifyDataSetChanged();
pd.dismiss();
}
public void goSearch(){
mTabHost.setCurrentTab(1);
//separate thread for making http request and updating the arraylist
Thread t = new Thread() {
public void run() {
searchResponse = sendSearchQuery(queryStr);
try{
JSONArray results = searchResponse.getJSONArray("results");
//this is stupid. i probably have to see how to make a json adapter
for(int index =0;index < results.length();index++){
JSONObject product = results.getJSONObject(index);
//gets the searched products from the json object
URL imgUrl = new URL(product.getString("image"));
String productname = product.getString("productname");
String ptypename = product.getString("ptypename");
int pid = product.getInt("pid");
int positive = product.getInt("pos");
int negative = product.getInt("neg");
int neutral = product.getInt("neu");
SearchItem item = new SearchItem(imgUrl,productname,ptypename,neutral,positive,negative,pid);
sResultsArr.add(item);
}
}
catch(JSONException e){
}
catch(Exception e){
}
//returns back to UI therad
h.post(mUpdateResults);
}
};
t.start();
}
//sends a request with qry as URL
//and receives back a JSONobject as response
public JSONObject sendSearchQuery(String qry){
HttpRequest r = new HttpRequest();
JSONObject response = r.sendHttpRequest(qry);
return response;
}
@Override
public boolean onDown(MotionEvent arg0) {
return gestureScanner.onTouchEvent(arg0);
}
@Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
Oh, noch eine Frage, wenn mein ListView
ein onItemClickListener
hat, kann Android zwischen einfachem oder doppeltem Tippen erkennen?
Warum verwenden Sie kein Long Press? Oder benutzt du das schon für etwas anderes? Die Vorteile einer langen Presse gegenüber einer doppelten Berührung:
Sie können den GestureDetector verwenden. Siehe den folgenden Code:
public class MyView extends View {
GestureDetector gestureDetector;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// creating new gesture detector
gestureDetector = new GestureDetector(context, new GestureListener());
}
// skipping measure calculation and drawing
// delegate the event to the gesture detector
@Override
public boolean onTouchEvent(MotionEvent e) {
return gestureDetector.onTouchEvent(e);
}
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
// event when double tap occurs
@Override
public boolean onDoubleTap(MotionEvent e) {
float x = e.getX();
float y = e.getY();
Log.d("Double Tap", "Tapped at: (" + x + "," + y + ")");
return true;
}
}
}
Sie können andere Methoden des Listeners überschreiben, um einzelne Taps, Flings usw. zu erhalten.
Als leichte Alternative zu GestureDetector können Sie diese Klasse verwenden
public abstract class DoubleClickListener implements OnClickListener {
private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds
long lastClickTime = 0;
@Override
public void onClick(View v) {
long clickTime = System.currentTimeMillis();
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){
onDoubleClick(v);
} else {
onSingleClick(v);
}
lastClickTime = clickTime;
}
public abstract void onSingleClick(View v);
public abstract void onDoubleClick(View v);
}
Beispiel:
view.setOnClickListener(new DoubleClickListener() {
@Override
public void onSingleClick(View v) {
}
@Override
public void onDoubleClick(View v) {
}
});
kombination von "Bughi" "DoubleClickListner" und "Jayant Arora" Timer in einer enthaltenen Klasse:
public abstract class DoubleClickListener implements OnClickListener {
private Timer timer = null; //at class level;
private int DELAY = 400;
private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds
long lastClickTime = 0;
@Override
public void onClick(View v) {
long clickTime = System.currentTimeMillis();
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){
processDoubleClickEvent(v);
} else {
processSingleClickEvent(v);
}
lastClickTime = clickTime;
}
public void processSingleClickEvent(final View v){
final Handler handler=new Handler();
final Runnable mRunnable=new Runnable(){
public void run(){
onSingleClick(v); //Do what ever u want on single click
}
};
TimerTask timertask=new TimerTask(){
@Override
public void run(){
handler.post(mRunnable);
}
};
timer=new Timer();
timer.schedule(timertask,DELAY);
}
public void processDoubleClickEvent(View v){
if(timer!=null)
{
timer.cancel(); //Cancels Running Tasks or Waiting Tasks.
timer.purge(); //Frees Memory by erasing cancelled Tasks.
}
onDoubleClick(v);//Do what ever u want on Double Click
}
public abstract void onSingleClick(View v);
public abstract void onDoubleClick(View v);
}
und kann aufgerufen werden als:
view.setOnClickListener(new DoubleClickListener() {
@Override
public void onSingleClick(View v) {
}
@Override
public void onDoubleClick(View v) {
}
});
wenn Sie sich nicht für eine benutzerdefinierte Ansicht entscheiden möchten, können Sie den folgenden Ansatz verwenden. z.B. Bildansicht
// class level
GestureDetector gestureDetector;
boolean tapped;
ImageView imageView;
// inside onCreate of Activity or Fragment
gestureDetector = new GestureDetector(context,new GestureListener());
// ------------------------------------------------ --------------------------------
public class GestureListener extends
GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
// event when double tap occurs
@Override
public boolean onDoubleTap(MotionEvent e) {
tapped = !tapped;
if (tapped) {
} else {
}
return true;
}
}
// ------------------------------------------------ --------------------------------
für ImageView
imageView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return gestureDetector.onTouchEvent(event);
}
});
Dies ist meine Lösung, es verwendet die Standardfunktion setOnItemClickListener()
. Ich hatte die gleiche Aufgabe zu implementieren. Bald werde ich ein Beispiel und eine benutzerdefinierte Klasse auf meinem Github posten .. Eine kurze Erklärung wird gegeben. Ich bin nicht sicher, ob die Zeit in Millisekunden der richtige Unterschied für das System ist (siehe ViewConfiguration.getDoubleTapTimeout()
source), um zwischen einfachem und doppeltem Tippen zu wählen.
Edit: Siehe hier: https://github.com/NikolaDespotoski/DoubleTapListView oder https://github.com/NikolaDespotoski/DoubleTapListViewHandler
GuestureDetecter funktioniert auf den meisten Geräten gut. Ich würde gerne wissen, wie die Zeit zwischen zwei Klicks bei einem Doppelklick-Ereignis angepasst werden kann. Ich konnte das nicht. Ich habe den obigen Code durch "Bughi" "DoubleClickListner" aktualisiert, einen Timer hinzugefügt, der einen Handler verwendet, der einen Code nach einer bestimmten Verzögerung mit einem einzigen Klick ausführt. Wenn vor dieser Verzögerung ein Doppelklick ausgeführt wird, bricht dies den Timer und die Single Click-Aufgabe ab und führt nur die Ausführung aus Doppelklick-Task . Code funktioniert. Fein Ermöglicht die Verwendung als Doppelklick-Listener:
private Timer timer = null; //at class level;
private int DELAY = 500;
view.setOnClickListener(new DoubleClickListener() {
@Override
public void onSingleClick(View v) {
final Handler handler = new Handler();
final Runnable mRunnable = new Runnable() {
public void run() {
processSingleClickEvent(v); //Do what ever u want on single click
}
};
TimerTask timertask = new TimerTask() {
@Override
public void run() {
handler.post(mRunnable);
}
};
timer = new Timer();
timer.schedule(timertask, DELAY);
}
@Override
public void onDoubleClick(View v) {
if(timer!=null)
{
timer.cancel(); //Cancels Running Tasks or Waiting Tasks.
timer.purge(); //Frees Memory by erasing cancelled Tasks.
}
processDoubleClickEvent(v);//Do what ever u want on Double Click
}
});
boolean nonDoubleClick = true, singleClick = false;
private long firstClickTime = 0L;
private final int DOUBLE_CLICK_TIMEOUT = 200;
listview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int pos, long id) {
// TODO Auto-generated method stub
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
if (singleClick) {
Toast.makeText(getApplicationContext(), "Single Tap Detected", Toast.LENGTH_SHORT).show();
}
firstClickTime = 0L;
nonDoubleClick = true;
singleClick = false;
}
}, 200);
if (firstClickTime == 0) {
firstClickTime = SystemClock.elapsedRealtime();
nonDoubleClick = true;
singleClick = true;
} else {
long deltaTime = SystemClock.elapsedRealtime() - firstClickTime;
firstClickTime = 0;
if (deltaTime < DOUBLE_CLICK_TIMEOUT) {
nonDoubleClick = false;
singleClick = false;
Toast.makeText(getApplicationContext(), "Double Tap Detected", Toast.LENGTH_SHORT).show();
}
}
}
});
Nur zweimal tippen
Ein doppeltes Antippen einer Ansicht lässt sich leicht mit SimpleOnGestureListener
erkennen (wie in Hannes Niederhausens Antwort gezeigt.
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
}
Ich sehe keinen großen Vorteil darin, die Logik dafür neu zu erfinden (wie Antwort von bughi ).
Doppeltippen und einmaliges Tippen mit Verzögerung
Sie können auch die Variable SimpleOnGestureListener
verwenden, um ein einzelnes Tippen und ein doppeltes Tippen als sich gegenseitig ausschließende Ereignisse zu unterscheiden. Dazu überschreiben Sie einfach onSingleTapConfirmed
. Dies verzögert die Ausführung des Single-Tap-Codes, bis das System sicher ist, dass der Benutzer nicht doppelt getippt hat (dh die Verzögerung> ViewConfiguration.getDoubleTapTimeout()
). Es gibt definitiv keinen Grund, die gesamte Logik dafür neu zu erfinden (wie dies in this , this und anderen Antworten geschieht).
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
}
Doppeltippen und einmaliges Tippen ohne Verzögerung
Das mögliche Problem mit onSingleTapConfirmed
ist die Verzögerung. Manchmal ist eine spürbare Verzögerung nicht akzeptabel. In diesem Fall können Sie onSingleTapConfirmed
durch onSingleTapUp
ersetzen.
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
}
Sie müssen jedoch wissen, dass sowohlonSingleTapUp
als auchonDoubleTap
aufgerufen werden, wenn Sie doppelt tippen. (Dies ist im Wesentlichen das, was bughis answer tut und worüber sich einige Kommentatoren beschwert haben. Sie müssen entweder die Verzögerung verwenden oder beide Methoden aufrufen. Es ist nicht möglich, einen einzelnen Tipp ohne Verzögerung auszuführen und gleichzeitig zu wissen, ob der Benutzer erneut tippen wird.
Wenn die Verzögerung mit einem Klick nicht akzeptabel ist, haben Sie mehrere Möglichkeiten:
onSingleTapUp
als auch onDoubleTap
für einen Doppeltipp aufgerufen werden. Teilen Sie Ihre Logik einfach so auf, dass es keine Rolle spielt. Dies ist im Wesentlichen das, was ich getan habe, als ich auf einer benutzerdefinierten Tastatur einen Doppeltipp für die Feststelltaste implementiert habe.Verwenden Sie kein Doppeltippen. Für die meisten Dinge ist es keine intuitive Benutzeroberflächenaktion. Wie Dave Webb schlägt vor, ist ein langes Drücken wahrscheinlich besser. Sie können das auch mit der SimpleOnGestureListener
implementieren:
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
}
}
Improvisierter Dhruvi-Code
public abstract class DoubleClickListener implements View.OnClickListener {
private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds
long lastClickTime = 0;
boolean tap = true;
@Override
public void onClick(View v) {
long clickTime = System.currentTimeMillis();
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){
onDoubleClick(v);
tap = false;
} else
tap = true;
v.postDelayed(new Runnable() {
@Override
public void run() {
if(tap)
onSingleClick();
}
},DOUBLE_CLICK_TIME_DELTA);
lastClickTime = clickTime;
}
public abstract void onDoubleClick(View v);
public abstract void onSingleClick();
}
public class MyView extends View {
GestureDetector gestureDetector;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// creating new gesture detector
gestureDetector = new GestureDetector(context, new GestureListener());
}
// skipping measure calculation and drawing
// delegate the event to the gesture detector
@Override
public boolean onTouchEvent(MotionEvent e) {
return gestureDetector.onTouchEvent(e);
}
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
// event when double tap occurs
@Override
public boolean onDoubleTap(MotionEvent e) {
float x = e.getX();
float y = e.getY();
Log.d("Double Tap", "Tapped at: (" + x + "," + y + ")");
return true;
}
}
}
Meine Lösung kann hilfreich sein.
long lastTouchUpTime = 0;
boolean isDoubleClick = false;
private void performDoubleClick() {
long currentTime = System.currentTimeMillis();
if(!isDoubleClick && currentTime - lastTouchUpTime < DOUBLE_CLICK_TIME_INTERVAL) {
isDoubleClick = true;
lastTouchUpTime = currentTime;
Toast.makeText(context, "double click", Toast.LENGTH_SHORT).show();
}
else {
lastTouchUpTime = currentTime;
isDoubleClick = false;
}
}
Realisierung Einzel- und Doppelklick
public abstract class DoubleClickListener implements View.OnClickListener {
private static final long DOUBLE_CLICK_TIME_DELTA = 200;
private long lastClickTime = 0;
private View view;
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
@Override
public void run() {
onSingleClick(view);
}
};
private void runTimer(){
handler.removeCallbacks(runnable);
handler.postDelayed(runnable,DOUBLE_CLICK_TIME_DELTA);
}
@Override
public void onClick(View view) {
this.view = view;
long clickTime = System.currentTimeMillis();
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){
handler.removeCallbacks(runnable);
lastClickTime = 0;
onDoubleClick(view);
} else {
runTimer();
lastClickTime = clickTime;
}
}
public abstract void onSingleClick(View v);
public abstract void onDoubleClick(View v);
}
Dies ist eine Lösung, die wartet, wenn ein zweiter Klick erfolgt, bevor eine Aktion ausgeführt wird
int init = 0;
myView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (init == 0) {
init++;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (init == 1) {
Log.d("hereGoes", "actionOne");
} else {
Log.d("hereGoes", "actionTwo");
}
init = 0;
}
}, 250);
} else {
init++;
}
}
});
Lösung von bughi & Jayant Arora für Copypast:
public abstract class DoubleClickListener implements View.OnClickListener {
private int position;
private Timer timer;
private static final long DOUBLE_CLICK_TIME_DELTA = 300;//milliseconds
long lastClickTime = 0;
public DoubleClickListener (int position) {
this.position = position;
}
@Override
public void onClick(View v) {
long clickTime = System.currentTimeMillis();
if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA){
if (timer != null) {
timer.cancel(); //Cancels Running Tasks or Waiting Tasks.
timer.purge(); //Frees Memory by erasing cancelled Tasks.
}
onDoubleClick(v, position);
} else {
final Handler handler = new Handler();
final Runnable mRunnable = () -> {
onSingleClick(v, position);
};
TimerTask timertask = new TimerTask() {
@Override
public void run() {
handler.post(mRunnable);
}
};
timer = new Timer();
timer.schedule(timertask, DOUBLE_CLICK_TIME_DELTA);
}
lastClickTime = clickTime;
}
public abstract void onSingleClick(View v, int position);
public abstract void onDoubleClick(View v, int position);}
sie können Doppeltippen mit der GestureDetectorCompat
-Klasse . in diesem Beispiel implementieren. Wenn Sie doppelt auf Textansicht tippen, können Sie Ihre Logik ausführen.
public class MainActivity extends AppCompatActivity {
GestureDetectorCompat gestureDetectorCompat;
TextView textElement;
@Override
protected void onCreate(Bundle savedInstanceState) {
.....
textElement = findViewById(R.id.textElement);
gestureDetectorCompat = new GestureDetectorCompat(this, new MyGesture());
textElement.setOnTouchListener(onTouchListener);
}
View.OnTouchListener onTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
gestureDetectorCompat.onTouchEvent(event);
return true;
}
};
class MyGesture extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
// whatever on double click
return true;
}
}
Ich verbringe viel Zeit, um diesen Code nach Kotlin zu konvertieren, hoffe, es spart jemandes Zeit
Erstellen Sie einen Gestenmelder:
val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
override fun onDoubleTap(e: MotionEvent): Boolean {
Toast.makeText([email protected],"Double Tap",Toast.LENGTH_LONG).show()
//Show or hide Ip address on double tap
toggleIPaddressVisibility()
return true;
}
override fun onLongPress(e: MotionEvent) {
super.onLongPress(e);
//rotate frame on long press
toggleFrameRotation()
Toast.makeText([email protected],"LongClick",Toast.LENGTH_LONG).show()
}
override fun onDoubleTapEvent(e: MotionEvent): Boolean {
return true
}
override fun onDown(e: MotionEvent): Boolean {
return true
}
})
Weisen Sie eine Ihrer Ansichten zu:
IPAddress.setOnTouchListener { v, event ->
[email protected] gestureDetector.onTouchEvent(event)
}
In diesem Beispiel habe ich den DoubleTap Listener mit einem Thread implementiert. Sie können meinen Listener mit jedem View-Objekt wie mit jedem ClickListener hinzufügen. Mit diesem Ansatz können Sie ganz einfach jede Art von Klick-Listener abrufen.
yourButton.setOnClickListener(new DoubleTapListener(this));
1) Meine Listrener Klasse
public class DoubleTapListener implements View.OnClickListener{
private boolean isRunning= false;
private int resetInTime =500;
private int counter=0;
private DoubleTapCallback listener;
public DoubleTapListener(Context context)
{
listener = (DoubleTapCallback)context;
Log.d("Double Tap","New");
}
@Override
public void onClick(View v) {
if(isRunning)
{
if(counter==1)
listener.onDoubleClick(v);
}
counter++;
if(!isRunning)
{
isRunning=true;
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(resetInTime);
isRunning = false;
counter=0;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
2) Listener Callback
public interface DoubleTapCallback {
public void onDoubleClick(View v);
}
3) Implementiere in deine Aktivität
public class MainActivity extends AppCompatActivity implements DoubleTapCallback{
private Button button;
private int counter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new DoubleTapListener(this)); // Set mt listener
}
@Override
public void onDoubleClick(View v) {
counter++;
textView.setText(counter+"");
}
Sie können den vollständigen Arbeitscode sehen HIER
Ich habe eine einfache benutzerdefinierte Methode mit kotlin coroutines implementiert (für Java kann es über Threads erfolgen).
var click = 0
view.setOnClickListener{
click++
clicksHandling()
}
fun clicksHandling() {
if (click == 1) {
launch {
delay(300) // custom delay duration between clicks
// if user didn't double tap then click counter still 1
if (click == 1) {
// single click handling
runOnUiThread {
// whatever you wanna do on UI thread
}
}
click = 0 //reset counter , this will run no matter single / double tap
}
//double click handling
if (click == 2) {
// whatever on double click
}
}
Äquivalenter C # -Code, mit dem ich dieselbe Funktionalität implementierte und sogar N Anzahl von Taps akzeptieren kann
public interface IOnTouchInterface
{
void ViewTapped();
}
public class MultipleTouchGestureListener : Java.Lang.Object, View.IOnTouchListener
{
int clickCount = 0;
long startTime;
static long MAX_DURATION = 500;
public int NumberOfTaps { get; set; } = 7;
readonly IOnTouchInterface interfc;
public MultipleTouchGestureListener(IOnTouchInterface tch)
{
this.interfc = tch;
}
public bool OnTouch(View v, MotionEvent e)
{
switch (e.Action)
{
case MotionEventActions.Down:
clickCount++;
if(clickCount == 1)
startTime = Utility.CurrentTimeSince1970;
break;
case MotionEventActions.Up:
var currentTime = Utility.CurrentTimeSince1970;
long time = currentTime - startTime;
if(time <= MAX_DURATION * NumberOfTaps)
{
if (clickCount == NumberOfTaps)
{
this.interfc.ViewTapped();
clickCount = 0;
}
}
else
{
clickCount = 0;
}
break;
}
return true;
}
}
public static class Utility
{
public static long CurrentTimeSince1970
{
get
{
DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
DateTime dtNow = DateTime.Now;
TimeSpan result = dtNow.Subtract(dt);
long seconds = (long)result.TotalMilliseconds;
return seconds;
}
}
}
Der derzeitige Code akzeptiert 7 als Anzahl von Taps, bevor er das View Tapped-Ereignis auslöst . Es kann jedoch mit einer beliebigen Anzahl angepasst werden