android自定义View及事件

来源:互联网 发布:截断数据库日志 编辑:程序博客网 时间:2024/06/05 03:39

直接如题,本例效果如下图,继承自ImageView,后面画了个圆,圆的大小在布局文件设置,点击圆内会有事件相应,圆外无响应。



先看自定义的MyView代码

[java]view plaincopy
  1. package test.bg;  

  2. import android.content.Context;  

  3. import android.content.res.TypedArray;  

  4. import android.graphics.Canvas;  

  5. import android.graphics.Paint;  

  6. import android.graphics.RectF;  

  7. import android.util.AttributeSet;  

  8. import android.util.Log;  

  9. import android.view.MotionEvent;  

  10. import android.view.ViewGroup.LayoutParams;  

  11. import android.view.ViewTreeObserver;  

  12. import android.view.ViewTreeObserver.OnGlobalLayoutListener;  

  13. import android.widget.ImageView;  

  14. publicclass MyView extends ImageView implements OnGlobalLayoutListener  

  15. {  

  16. privateint radius = 0;  

  17. private RectF rectF = null;  

  18. private test.bg.OnTouchListener mOnTouchListener=null;  

  19. public MyView(Context context)  

  20.    {  

  21. super(context);  

  22.        TypedArray ta = context.obtainStyledAttributes(R.styleable.MyView);  

  23.        radius = ta.getDimensionPixelSize(R.styleable.MyView_radius, 0);  

  24.        rectF = new RectF(0, 0, 2 * radius, 2 * radius);  

  25.        ta.recycle();  

  26.        ViewTreeObserver vto = getViewTreeObserver();  

  27.        vto.addOnGlobalLayoutListener(this);  

  28.    }  

  29. public MyView(Context context, AttributeSet attrs, int defStyle)  

  30.    {  

  31. super(context, attrs, defStyle);  

  32.        TypedArray ta = context.obtainStyledAttributes(attrs,  

  33.                R.styleable.MyView);  

  34.        radius = ta.getDimensionPixelSize(R.styleable.MyView_radius, 0);  

  35.        rectF = new RectF(0, 0, 2 * radius, 2 * radius);  

  36.        ta.recycle();  

  37.        ViewTreeObserver vto = getViewTreeObserver();  

  38.        vto.addOnGlobalLayoutListener(this);  

  39.    }  

  40. public MyView(Context context, AttributeSet attrs)  

  41.    {  

  42. super(context, attrs);  

  43.        TypedArray ta = context.obtainStyledAttributes(attrs,  

  44.                R.styleable.MyView);  

  45.        radius = ta.getDimensionPixelSize(R.styleable.MyView_radius, 0);  

  46.        rectF = new RectF(0, 0, 2 * radius, 2 * radius);  

  47.        ta.recycle();  

  48.        ViewTreeObserver vto = getViewTreeObserver();  

  49.        vto.addOnGlobalLayoutListener(this);  

  50.    }  

  51. publicvoid setOnTouchListener(test.bg.OnTouchListener mOnTouchListener){  

  52. this.mOnTouchListener=mOnTouchListener;  

  53.    }  

  54. @Override

  55. protectedvoid onDraw(Canvas canvas)  

  56.    {  

  57.        Paint p = new Paint();  

  58.        p.reset();  

  59.        p.setARGB(255, 255, 0, 0);  

  60.        canvas.drawRoundRect(rectF, radius, radius, p);  

  61. super.onDraw(canvas);  

  62.    }  

  63. @Override

  64. publicvoid onGlobalLayout()  

  65.    {  

  66.        LayoutParams lp = getLayoutParams();  

  67.        lp.height = 2 * radius;  

  68.        lp.width = 2 * radius;  

  69.        setLayoutParams(lp);  

  70.    }  

  71. @Override

  72. publicboolean onTouchEvent(MotionEvent event)  

  73.    {  

  74. float x = event.getX();  

  75. float y = event.getY();  

  76. if ((x-radius)*(x-radius)+(y-radius)*(y-radius)<radius*radius)  

  77.        {  

  78.            Log.d("nei", ""+x+":"+y);  

  79. return mOnTouchListener.onTouchEvent(this, event);  

  80.        }  

  81. else

  82.        {  

  83.            Log.d("wai", ""+x+":"+y);  

  84. returnfalse;  

  85.        }  

  86.    }  

  87. }  

其中TypedArray ta = context.obtainStyledAttributes(R.styleable.MyView);
       radius = ta.getDimensionPixelSize(R.styleable.MyView_radius, 0);


涉及到的代码事先在res/valus下新建attrs.xml并加入内容

[html]view plaincopy
  1. <?xmlversion="1.0"encoding="utf-8"?>

  2. <resources>

  3. <declare-styleablename="MyView">

  4. <attrname="radius"format="dimension"/>

  5. </declare-styleable>

  6. </resources>

即定义了属性和属性类型,在布局文件设置属性时需要加入xmlns:gain="http://schemas.android.com/apk/res/test.bg",其中gain是属性的前缀,test.bg是包名,完整布局文件如下
[html]view plaincopy
  1. <?xmlversion="1.0"encoding="utf-8"?>

  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

  3. xmlns:gain="http://schemas.android.com/apk/res/test.bg"

  4. android:layout_width="fill_parent"

  5. android:layout_height="fill_parent"

  6. android:orientation="vertical">

  7. <test.bg.MyView

  8. android:id="@+id/mv"

  9. android:layout_width="wrap_content"

  10. android:layout_height="wrap_content"

  11. gain:radius="160dp"

  12. android:src="@drawable/ic_launcher">

  13. </test.bg.MyView>

  14. </LinearLayout>

接下就可以直接用MyView了,代码如下
[java]view plaincopy
  1. package test.bg;  

  2. import android.app.Activity;  

  3. import android.os.Bundle;  

  4. import android.view.MotionEvent;  

  5. import android.view.View;  

  6. import android.widget.Toast;  

  7. publicclass TestBgActivity extends Activity implements OnTouchListener  

  8. {  

  9.    MyView mv;  

  10. /** Called when the activity is first created. */

  11. @Override

  12. publicvoid onCreate(Bundle savedInstanceState)  

  13.    {  

  14. super.onCreate(savedInstanceState);  

  15.        setContentView(R.layout.main);  

  16.        MyView mv = (MyView) findViewById(R.id.mv);  

  17.        mv.setOnTouchListener(this);  

  18.    }  

  19. @Override

  20. publicboolean onTouchEvent(View v, MotionEvent event)  

  21.    {  

  22. if (v.getId() == R.id.mv)  

  23.        {  

  24.            Toast.makeText(this,  

  25. "haha:" + v.getId() + ":" + event.getX() + ":"

  26.                            + event.getY(),  

  27.                    Toast.LENGTH_SHORT).show();  

  28.        }  

  29. returnfalse;  

  30.    }  

  31. }  

注意到这里的OnTouchListener并不是系统的OnTouchListener,而是我们自己定义的一个,只不过名称相同而已,定义如下
[java]view plaincopy
  1. package test.bg;  

  2. import android.view.MotionEvent;  

  3. import android.view.View;  

  4. publicinterface OnTouchListener  

  5. {  

  6. publicboolean onTouchEvent(View v, MotionEvent event);  

  7. }  

为什么要自己定义OnTouchListener?因为android的传统控件都是都是以矩形区域来响应事件的,而自定义的控件可以根据自己需要的形状来响应事件,比如本例的圆形事件区响应,而不在圆内,即使是在圆的外接矩形内也不能响应,因为我们在MyView里面实现了View的onTouchEvent(MotionEvent event)方法从而进行过滤,即代码
[java]view plaincopy
  1. @Override

  2. publicboolean onTouchEvent(MotionEvent event)  

  3.   {  

  4. float x = event.getX();  

  5. float y = event.getY();  

  6. if ((x-radius)*(x-radius)+(y-radius)*(y-radius)<radius*radius)  

  7.       {  

  8.           Log.d("nei", ""+x+":"+y);  

  9. return mOnTouchListener.onTouchEvent(this, event);  

  10.       }  

  11. else

  12.       {  

  13.           Log.d("wai", ""+x+":"+y);  

  14. returnfalse;  

  15.       }  

  16.   }  


即事件发生在圆内就触发自定义方法,圆外的直接忽略。


That's all!nice day,isn't it?


0 0
原创粉丝点击