Android 自定义View实现单击和双击事件的方法
程序员文章站
2024-03-04 20:05:30
自定义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实现单击和双击事件的方法的全部内容了,希望对大家有所帮助,多多支持~