欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-03-05 18:58:07
自定义view, 1. 自定义一个runnable线程toucheventcountthread ,  用来统计500ms内的点击次数 2. 在myview中...

自定义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实现单击和双击事件的方法的全部内容了,希望对大家有所帮助,多多支持~