Klick-Effekt bei Doppelklick ausschalten?

  • 7 Antworten
  • Letztes Antwortdatum
N

no1Ltan

Fortgeschrittenes Mitglied
7
Hallo,

ich versuche in dieser kleinen Test-App, die aus nur 1 Activity und 1 TextView besteht, folgendes:
Beim Klick auf die TextView soll einfach der Wert innerhalb der TextView mit 1 addiert werden.

Zusätzlich soll es einen Klick-Effekt geben (visuelles Feedback) und es soll verhindert werden, dass ein Doppelklick möglich ist.
Beim Doppelklick soll also nicht addiert werden und der Klick-Effekt soll auch nicht an sein.

Habe es hinbekommen, dass der Doppelklick nicht funktioniert und den Klick-Effekt habe ich auch hinbekommen.
Leider schaffe ich es nicht, den Klick-Effekt kurzzeitig zu deaktivieren.
Ich dachte, SystemClock.sleep(1000); würde mir da helfen, aber das sorgt einfach nur für eine Verzögerung in der Methode.

Das ist der Code:
Code:
import android.content.res.TypedArray;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity
{
    private int count;
    private long mLastClickTime = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textViewCount = findViewById(R.id.text_view_count);
        textViewCount.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) // If second click is within 1 second:
                {
                    return; // Don't execute code below
                }
                mLastClickTime = SystemClock.elapsedRealtime(); // Reset mLastClickTime
                rippleEffect(); // Add click effect
                count++; // Increment counter by 1
                String countText = Integer.toString(count); // Cast int to String
                textViewCount.setText(countText); // Show String value in TextView
            }
        });
    }
    public void rippleEffect() // Add click effect
    {
        TextView textViewCount = findViewById(R.id.text_view_count); // Link ID with variable
        int[] attrs = new int[]{R.attr.selectableItemBackground};
        TypedArray typedArray = obtainStyledAttributes(attrs);
        int backgroundResource = typedArray.getResourceId(0, 0);
        textViewCount.setBackgroundResource(backgroundResource);
        textViewCount.setClickable(false); // Set clickable to false
        SystemClock.sleep(1000); // Add delay of 1 s - BAD IDEA!
        textViewCount.setClickable(true); // Set clickable to true again
    }
}

Wie bekomme ich es hin, dass auch der Klick-Effekt aus ist, wenn der Counter nicht hochgezählt wird?

Bezüglich des Hintergrundes in der TextView ist auch einiges unklar... aber eins nach dem anderen.

Grüße
 
Hallo,

unter Android gibt es in dem Sinne kein "Sleep".
Zeitverzögerungen sollten daher mittels Thread ausgeführt werden -
So wie du es oben anwendest läuft es nicht frei und du blockierst das UI-System

Bsp :
Code:
 Handler handler = new Handler();
                    handler.postDelayed(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                          // Do
                        }                       
                    }, 1000);

Vielmehr würde ich Dir anraten, das Ganze in einem AsyncTask zu betten .
Du kannst auch einen OnTouchListener verwenden , um einen Doppelclick abzufangen
 
Zuletzt bearbeitet:
Versuche es mal so


Code:
     if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) // If second click is within 1 second:
                {
                    mLastClickTime = SystemClock.elapsedRealtime(); // Reset mLastClickTime
                    return; // Don't execute code below
                }
                mLastClickTime = SystemClock.elapsedRealtime(); // Reset mLastClickTime
                rippleEffect(); // Add click effect
                count++; // Increment counter by 1
                String countText = Integer.toString(count); // Cast int to String
                textViewCount.setText(countText); // Show String
 
Hab's (unsauber) gelöst.
Die Frage ist, ob es auch bei einer "echten App" funktionieren wird, wenn der Hintergrund
aus einer SharedPreferences kommt.
(Da würde dann statt R.color.red eben eine Variable stehen.)

Code:
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity
{
    private int count;
    private long mLastClickTime = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textViewCount = findViewById(R.id.text_view_count);
        textViewCount.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) // 1 second
                {
                    textViewCount.setBackgroundResource(R.color.red);
                    return;
                }
                mLastClickTime = SystemClock.elapsedRealtime();
                rippleEffect();
                count++;
                String countText = Integer.toString(count);
                textViewCount.setText(countText);
            }
        });
    }
    public void rippleEffect()
    {
        TextView textViewCount = findViewById(R.id.text_view_count);
        int[] attrs = new int[]{R.attr.selectableItemBackground};
        TypedArray typedArray = obtainStyledAttributes(attrs);
        int backgroundResource = typedArray.getResourceId(0, 0);
        textViewCount.setBackgroundResource(backgroundResource);
    }
}

In diesem Fall wird der originale Hintergrund der TextView wieder hergestellt,
falls man innerhalb 1 Sekunde nochmal klickt.

@jogimuc:
Habe deinen Code versucht, aber keinen Unterschied gemerkt.
Trotzdem danke!

@swa00:
Also ich hatte es probiert, aber das einzige, was anders war, war der fehlende Klick-Effekt
beim ersten Klick.
Kann aber natürlich trotzdem sein, dass ich was falsch gemacht habe.

Zusätzlich versuchte ich noch die clickable kurzzeitig auf false zu setzen.
Allerdings wurde die nie wieder auf true gesetzt.

Code:
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity
{
    private int count;
    private long mLastClickTime = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textViewCount = findViewById(R.id.text_view_count);
        textViewCount.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) // 1 second
                {
                    return;
                }
                mLastClickTime = SystemClock.elapsedRealtime();
                rippleEffect();
                count++;
                String countText = Integer.toString(count);
                textViewCount.setText(countText);
            }
        });
    }
    public void rippleEffect()
    {
        final TextView textViewCount = findViewById(R.id.text_view_count);
        Handler handler = new Handler();
        handler.postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                int[] attrs = new int[]{R.attr.selectableItemBackground};
                TypedArray typedArray = obtainStyledAttributes(attrs);
                int backgroundResource = typedArray.getResourceId(0, 0);
                textViewCount.setBackgroundResource(backgroundResource);
                textViewCount.setClickable(false);
            }
        }, 1000);
        textViewCount.setClickable(true);
    }
}

P.S. Die final TextView brauche ich, damit die "innere Klasse" auch drauf zugreifen kann.

Grüße
 
Hallo,
ist schon etwas länger her, aber ich wollte keinen neuen Thread erstellen.

Hab mir jetzt angewohnt, viel mehr mit Methoden zu arbeiten, um eine bessere Übersicht zu haben.

Allerdings schaffe ich es mit diesem "PreventDoubleClick" einfach nicht.
Wenn ich diesen Codeblock verwende, funktioniert es einwandfrei:

Code:
    textView1.setOnClickListener(new View.OnClickListener()
    {
        @Override public void onClick(View v)
        {
            if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) // If user already clicked within 1 second:
            {
                return; // Don't execute code below
            }
            mLastClickTime = SystemClock.elapsedRealtime(); // Reset mLastClickTime
            count++; // Increment count by 1
            moveEffect(textView1); // Start moving animation
        }
    });

Bei diesem funktioniert es aber nicht:
Code:
    textView1.setOnClickListener(new View.OnClickListener()
    {
        @Override public void onClick(View v)
        {
            preventDoubleClick();
            count++; // Increment count by 1
            moveEffect(textView1); // Start moving animation
        }
    });

public void preventDoubleClick()
{
  if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) // If user clicks second time within 1 second:
  {
      return; // Don't execute code below
  }
  mLastClickTime = SystemClock.elapsedRealtime(); // Reset mLastClickTime
}


Dass es nicht funktioniert, ergibt für mich sogar Sinn.
Soweit ich das einschätzen kann, bezieht sich das return auf die 1 Codezeile innerhalb der Methode.

Im Beispiel oben bezieht sich das return auf die 3 Codezeilen des onClickListeners.

Wie müsste ich die Methode schreiben, so dass sie auch für das Beispiel 2 funktioniert?
Klar könnte ich eine if-Abfrage machen, aber dann wäre es fast wie Beispiel 1.

Keine große Sache, aber es interessiert mich dennoch.
Wenn es technisch nicht möglich ist, habe ich wenigstens wieder was dazu gelernt.

Grüße
 
Um den Control Flow einer Methode A zu verlassen die eine andere Methode B gecallt hat bleibt B nur eine Exception. Alternativ halt in B ein boolen zurückgeben und in A checken. Aber wie du sagst sieht es dann aus wie vorher.
Exception würde ich nicht empfehlen in diesem Fall.
 
Eine Lösung wäre es mit einen Rückgabewert zu machen.
Code:
textView1.setOnClickListener(new View.OnClickListener()
    {
        @Override public void onClick(View v)
        {
            if(!preventDoubleClick()) return;
            count++; // Increment count by 1
            moveEffect(textView1); // Start moving animation
        }
    });

public boolean preventDoubleClick()
{
  if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) // If user clicks second time within 1 second:
  {
      return false; // Don't execute code below
  }
  mLastClickTime = SystemClock.elapsedRealtime(); // Reset mLastClickTime
  return true;
}
 
  • Danke
Reaktionen: no1Ltan
Mir fällt noch ne schöne Variante mit Lambdas ein falls du Java 8 Source aktiviert hast.

Code:
   textView1.setOnClickListener(new View.OnClickListener()  {
       @Override public void onClick(View v)
       {
           executeForSingleClick(() -> {
              count++; // Increment count by 1
              moveEffect(textView1); // Start moving animation
           });
       }
   });

public void executeForSingleClick(Runnable callback) {
  if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) // If user clicks second time within 1 second:
  {
     return; // Don't execute code below
  }
  mLastClickTime = SystemClock.elapsedRealtime(); // Reset mLastClickTime
  callback.run();
}

Auch wenn ich aus den bisherigen Posts von dir rausgelesen habe, dass du wohl kein Fan davon bist.
 
  • Danke
Reaktionen: no1Ltan
Zurück
Oben Unten