当前位置: 移动技术网 > 移动技术>移动开发>Android > Android 自定义View实现单击和双击事件的方法

Android 自定义View实现单击和双击事件的方法

2019年07月24日  | 移动技术网移动技术  | 我要评论

自定义view,

1. 自定义一个runnable线程toucheventcountthread ,  用来统计500ms内的点击次数

2. 在myview中的 ontouchevent 中调用 上面的线程

3. 自定义一个handler, 在toucheventhandler 中 处理 统计到的点击事件, 单击, 双击, 三击, 都可以处理

核心代码如下: 

public class myview extends view {

  ......

  // 统计500ms内的点击次数
  toucheventcountthread mintoucheventcount = new toucheventcountthread();
  // 根据toucheventcountthread统计到的点击次数, perform单击还是双击事件
  toucheventhandler mtoucheventhandler = new toucheventhandler();

  @override
  public boolean ontouchevent(motionevent event) {
    switch (event.getaction()) {
      case motionevent.action_down:
        if (0 == mintoucheventcount.touchcount) // 第一次按下时,开始统计
          postdelayed(mintoucheventcount, 500);
        break;
      case motionevent.action_up:
        // 一次点击事件要有按下和抬起, 有抬起必有按下, 所以只需要在action_up中处理
        mintoucheventcount.touchcount++;
        // 如果是长按操作, 则handler的消息,不能将touchcount置0, 需要特殊处理
        if(mintoucheventcount.islongclick) {
          mintoucheventcount.touchcount = 0;
          mintoucheventcount.islongclick = false;
        }
        break;
      case motionevent.action_move:
        break;
      case motionevent.action_cancel:
        break;
      default:
        break;
    }

    return super.ontouchevent(event);
  }

  public class toucheventcountthread implements runnable {
    public int touchcount = 0;
    public boolean islongclick = false;

    @override
    public void run() {
      message msg = new message();
      if(0 == touchcount){ // long click
        islongclick = true;
      } else {
        msg.arg1 = touchcount;
        mtoucheventhandler.sendmessage(msg);
        touchcount = 0;
      }
    }
  }

  public class toucheventhandler extends handler {

    @override
    public void handlemessage(message msg) {
      toast.maketext(mcontext, "touch " + msg.arg1 + " time.", toast.length_short).show();
    }
  }

  ......

}

包装以后如下, 这样就能在别的地方调用了:

public interface ondoubleclicklistener{
    void ondoubleclick(view v);
  }
  
  private ondoubleclicklistener mondoubleclicklistener;

  public void setondoubleclicklistener(myview.ondoubleclicklistener l) {
    mondoubleclicklistener = l;
  }

  public boolean performdoubleclick() {
    boolean result = false;
    if(mondoubleclicklistener != null) {
      mondoubleclicklistener.ondoubleclick(this);
      result = true;
    }
    return result;
  }

  public class toucheventhandler extends handler {

    @override
    public void handlemessage(message msg) {
      if(2 == msg.arg1)
        performdoubleclick();
    }
  }

在activity中使用

myview1.setondoubleclicklistener(new myview.ondoubleclicklistener() {
  @override
  public void ondoubleclick(view v) {
  toast.maketext(mcontext,"double click", toast.length_short).show();
  }
});

全部代码

myview.java

package com.carloz.test.myapplication.view;

import android.content.context;
import android.content.res.typedarray;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.paint;
import android.os.handler;
import android.os.message;
import android.util.attributeset;
import android.view.motionevent;
import android.view.view;
import android.widget.toast;

import com.carloz.test.myapplication.r;

/**
 * created by root on 15-11-9.
 */
public class myview extends view {

  private paint mpaint = new paint();
  private boolean mnotdestroy = true;
  private int mcount = 0;
  private mythread mythread;
  bitmap bitmap;
  // attrs
  private string mtext;
  private boolean mstartchange;
  context mcontext;


  public myview(context context) {
    super(context);
    init();
  }

  public myview(context context, attributeset attrs) {
    super(context, attrs);
    typedarray ta = context.obtainstyledattributes(attrs, r.styleable.myview);
    mtext = ta.getstring(r.styleable.myview_text);
    mstartchange = ta.getboolean(r.styleable.myview_startchange, false);
    // log.d("asdf", "mtext=" + mtext + ", mstartchange=" + mstartchange);
    ta.recycle();

    init();
  }

  @override
  protected void onfinishinflate() {
    super.onfinishinflate();
  }

  @override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    super.onmeasure(widthmeasurespec, heightmeasurespec);
  }

  @override
  protected void onlayout(boolean changed, int left, int top, int right, int bottom) {
    super.onlayout(changed, left, top, right, bottom);
  }

  @override
  protected void ondraw(canvas canvas) {
    super.ondraw(canvas);
    mpaint.settextsize(50);
    canvas.drawtext(mtext + mcount++, 20f, 100f, mpaint);
    canvas.save();
    canvas.rotate(60, getwidth() / 2, getheight() / 2);
    canvas.drawbitmap(bitmap, 20f, 50f, mpaint);
    canvas.restore();

    if (null == mythread) {
      mythread = new mythread();
      mythread.start();
    }
  }

  @override
  public boolean dispatchtouchevent(motionevent ev) {
    return super.dispatchtouchevent(ev);
  }

  @override
  protected void onattachedtowindow() {
    super.onattachedtowindow();
    mnotdestroy = true;
  }

  @override
  protected void ondetachedfromwindow() {
    mnotdestroy = false;
    super.ondetachedfromwindow();
  }

  // 统计500ms内的点击次数
  toucheventcountthread mintoucheventcount = new toucheventcountthread();
  // 根据toucheventcountthread统计到的点击次数, perform单击还是双击事件
  toucheventhandler mtoucheventhandler = new toucheventhandler();

  @override
  public boolean ontouchevent(motionevent event) {
    switch (event.getaction()) {
      case motionevent.action_down:
        if (0 == mintoucheventcount.touchcount) // 第一次按下时,开始统计
          postdelayed(mintoucheventcount, 500);
        break;
      case motionevent.action_up:
        // 一次点击事件要有按下和抬起, 有抬起必有按下, 所以只需要在action_up中处理
        mintoucheventcount.touchcount++;
        // 如果是长按操作, 则handler的消息,不能将touchcount置0, 需要特殊处理
        if(mintoucheventcount.islongclick) {
          mintoucheventcount.touchcount = 0;
          mintoucheventcount.islongclick = false;
        }
        break;
      case motionevent.action_move:
        break;
      case motionevent.action_cancel:
        break;
      default:
        break;
    }

    return super.ontouchevent(event);
  }

  public class toucheventcountthread implements runnable {
    public int touchcount = 0;
    public boolean islongclick = false;

    @override
    public void run() {
      message msg = new message();
      if(0 == touchcount){ // long click
        islongclick = true;
      } else {
        msg.arg1 = touchcount;
        mtoucheventhandler.sendmessage(msg);
        touchcount = 0;
      }
    }
  }

  public class toucheventhandler extends handler {

    @override
    public void handlemessage(message msg) {
      toast.maketext(mcontext, "touch " + msg.arg1 + " time.", toast.length_short).show();
    }
  }

  class mythread extends thread {

    @override
    public void run() {
      super.run();
      while (mnotdestroy) {
        if (mstartchange) {
          postinvalidate();
          try {
            thread.sleep(500);
          } catch (interruptedexception e) {
            e.printstacktrace();
          }
        }
      }
    }
  }

  public void init() {
    mcontext = getcontext();
    bitmap = bitmapfactory.decoderesource(getresources(), r.drawable.ic_launcher);
  }

  public void settext(string mtext) {
    this.mtext = mtext;
  }

  public void setstartchange(boolean mstartchange) {
    this.mstartchange = mstartchange;
  }

  public boolean getstartchange() {
    return this.mstartchange;
  }
}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-styleable name="myview">
    <attr name="text" format="string"/>
    <attr name="startchange" format="boolean"/>
  </declare-styleable>

</resources>

postdelayed方法最终是靠 handler 的 postdelayed 方法 实现原理如下

public final boolean postdelayed(runnable r, long delaymillis)
  {
    return sendmessagedelayed(getpostmessage(r), delaymillis);
  }

  public final boolean sendmessagedelayed(message msg, long delaymillis)
  {
    if (delaymillis < 0) {
      delaymillis = 0;
    }
    return sendmessageattime(msg, systemclock.uptimemillis() + delaymillis);
  }

  public boolean sendmessageattime(message msg, long uptimemillis) {
    messagequeue queue = mqueue;
    if (queue == null) {
      runtimeexception e = new runtimeexception(
          this + " sendmessageattime() called with no mqueue");
      log.w("looper", e.getmessage(), e);
      return false;
    }
    return enqueuemessage(queue, msg, uptimemillis); // 然后在messagequeue中会比较时间顺序
  }

以上就是小编为大家带来的android 自定义view实现单击和双击事件的方法的全部内容了,希望对大家有所帮助,多多支持移动技术网~

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网