多点触控事件简单介绍
最关键的是onTouchEvent这个方法明天应该就会继续介绍比这要更加多的于事件相关的,比如事件分发等,今天是简单的事件,不多说,如下:
单指 4个动作 + x值 和 y 值
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
重写onTouchEvent就好了,这里面有好几个事件,准确说是一组事件分别是:
- MotionEvent.ACTION_DOWN 手指按下
- MotionEvent.ACTION_MOVE 手指移动
- ACTION_UP 手指抬起
- ACTION_CANCEL 取消,这里看来和up没什么区别,和事件分发有关,这里就不详细讲了,可能明天就学了(笑);
以上就是简单的介绍,接下来实现一个简单的案例 简单的画画板
package com.zhouzhou.flowlayoutdemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by zhousaito on 2016/9/7.
*/
public class TouchView extends View {
private Paint mPaint;
private Path mPath;
private float mLastX;
private float mLastY;
private int mPenColor;
private int mPenSize;
public TouchView(Context context) {
this(context, null);
}
public TouchView(Context context, AttributeSet attrs) {
this(context, attrs, R.style.MyDefStyle);
}
public TouchView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TouchView, defStyleAttr, R.style.MyDefStyle);
for (int i = 0; i < array.getIndexCount(); i++) {
int index = array.getIndex(i);
switch (index) {
case R.styleable.TouchView_penColor:
mPenColor = array.getColor(index, Color.RED);
break;
case R.styleable.TouchView_penSize:
mPenSize = array.getDimensionPixelSize(index, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
break;
}
}
mPaint = new Paint();
mPath = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mPenSize);
mPaint.setColor(mPenColor);
//画上线条
canvas.drawPath(mPath,mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastX = event.getX();
mLastY = event.getY();
mPath.moveTo(mLastX, mLastY);
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(event.getX(), event.getY());
mLastX = event.getX();
mLastY = event.getY();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
}
//重写绘制
invalidate();
return true;
}
}
这里加了一些属性和style
在 attrs.xml文件中定义
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
设置默认样式(style)
这个 parent="android:Widget" 为了表示是一个属性
这样就可以应用,可以不写
-->
<style name="MyDefStyle" parent="android:Widget">
<item name="penColor">#ff0</item>
<item name="penSize">5dp</item>
</style>
<declare-styleable name="TouchView">
<attr name="penColor" format="color"/>
<attr name="penSize" format="dimension"/>
</declare-styleable>
</resources>
然后代码引用上就好了,这样,简单的画板就完成了,哈哈
接下来学一下 Matrix API 我没怎么搞懂,还是说一下吧,
用画图来解释吧,Matrix 矩阵,有几种方式
1.缩放,这个简单,就要知道mMatrix.postScale(0.5f,0.5f,100,100);
前面是缩放比例,后面是旋转中心点,不写就是绕着父控件的左上角缩放
2.旋转,mMatrix.postRotate(10,100,100); 和缩放差不多,
3.平移 mMatrix.postTranslate(10,10); 就是移动
4.倾斜 mMatrix.postSkew(0.1f,0);
上面4个属性简单,我就不写了,网上一大堆,其实学属性动画时候就有学到这些,就倾斜没有,然而这属性并不常用,其实我想上gif 图片的,感觉自己想傻吊一样,这上gif,太占资源吧,4个属性4个图
多手指触控事件
event.getActionMasked(); 并不是event.getAction(),而是通过event.getActionMasked()这值来判断,是否多手指的触控的
MotionEvent.ACTION_POINTER_DOWN 按下
MotionEvent.ACTION_MOVE 移动(和单手指一样的)
MotionEvent.ACTION_POINTER_UP 抬起
这样就可以做对应的事情了,
**[0] 主要和单手指冲突时,可以根据event.getPointerCount()
来判断多少个手指,然后做对应的事情**
继承ViewGroup 的自定义
今天是继承ViewGroup来实现自定义控件
FlowLayout(流式布局) 其实很简单,但是自己没那么有逻辑,先不废话了
[1] TODO --> onLayout() -->里面的值
[2] 用recycleView来实现一个流式布局
[3] 必须到onMeasure中写 measureChildren(); 才可以显示 不然不能显示
第一步 继承viewGroup
public class FlowLayout extends ViewGroup {
public FlowLayout(Context context) {
super(context);
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
继承完之后,我们的目标是flowLayout 所以更具需求来写
/**
* MeasureSpec.UNSPECIFIED
* --->子控件自己的大小来显示,所以怎么设置值都没什么用
* 二级缓存绘制
* [1] TODO --> onLayout() -->里面的值
* [2] 用recycleView来实现一个流式布局
* [3] 必须到onMeasure中写 measureChildren(); 才可以显示 不然不能显示
* @param changed
* @param l 父控件的位置
* @param t
* @param r
* @param b
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//流式布局 从左边到右边开始排
int left = l;
int maxHeight =0;
int top = t;
//总宽度
int width = r - l;
for (int i = 0; i < getChildCount(); i++) {
//得到子类控件
View view = getChildAt(i);
// Log.e("自定义标签", "类名==FlowLayout" + "方法名==onLayout=====:" );
//
if (left + view.getMeasuredWidth() > width) {
top += maxHeight;
maxHeight=0;
left =l;
}
view.layout(left,top,left+view.getMeasuredWidth(),top+view.getMeasuredHeight());
left+=view.getMeasuredWidth();
maxHeight = Math.max(maxHeight, view.getMeasuredHeight());
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 要写这个才能显示
*/
// measureChildren(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
measureChildren(widthMeasureSpec,heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
这样大概实现了一下,因为没有重写onMeasure()方法,所以,flowLayout的宽和高不管用,都是满上了父控件(可以说match_parent,因为表现是充满的)
这样的话,如果给 flowlayout 加一个padding的话,就看出来,我们的工程并没有完成
先说好,布局是6个textView和6个机器人图标交错,就是几行复制的,哈哈
<com.zhouzhou.flowlayoutdemo.FlowLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00f"
android:padding="50dp">
<!--加了50的padding-->
就成这样了,发现是自己没有处理padding和margin
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = getPaddingLeft();
int maxHeight = 0;
int top = getPaddingTop();
int width = r - l - getPaddingLeft() - getPaddingRight();
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
if (left + view.getMeasuredWidth() > width) {
top += maxHeight;
maxHeight = 0;
left = getPaddingLeft();
}
view.layout(left + params.leftMargin,
top + params.topMargin,
left + params.leftMargin + view.getMeasuredWidth(),
top + params.topMargin + view.getMeasuredHeight());
left += view.getMeasuredWidth() + params.leftMargin + params.rightMargin;
maxHeight = Math.max(maxHeight, view.getMeasuredHeight() + params.topMargin + params.bottomMargin);
}
}
加了些padding的处理效果 (背景我去了,看着头晕(笑))
接下来写onMeasure() 方法,来决定 父控件自身的宽度,从而可以通过高和宽,来进行显示,这样,可以平常使用就差不多了,哈哈
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 要写这个才能显示
*/
// measureChildren(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
measureChildren(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width = 0;
int height = 0;
//只要不是固定的 就
if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
int left = getPaddingLeft();
int maxHeight = 0;
int top = getPaddingTop();
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
//相加后,通过原来的
if (left + view.getMeasuredWidth() + params.rightMargin + params.leftMargin > widthSize - getPaddingRight()) {
top += maxHeight;
maxHeight = 0;
//在这里得到的是left的,相当于这排排满了的最大宽度
width = Math.max(width, left);
left = getPaddingLeft();
}
left += view.getMeasuredWidth() + params.rightMargin + params.leftMargin;
maxHeight = Math.max(maxHeight, view.getMeasuredHeight() + params.topMargin + params.bottomMargin);
}
height = maxHeight + top + getPaddingTop() + getPaddingBottom();
switch (widthMode) {
case MeasureSpec.AT_MOST:
width = Math.min(width,widthSize);
break;
case MeasureSpec.UNSPECIFIED:
width = widthSize;
break;
}
switch (heightMode) {
case MeasureSpec.AT_MOST:
//容器的高度
height = Math.min(heightSize, height);
break;
case MeasureSpec.UNSPECIFIED:
//容器的高度
height = heightSize;
break;
}
}else {
//固定的就用自己固定的高和宽
width =widthSize;
height = heightSize;
}
setMeasuredDimension(width, height);
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
写完这些,哈哈,基本完成了,简单的继承了viewGroup然后,自己写了一个简单的容器,flowlayout,效果如下
结果,还是比较丑,哈哈
以上就今天的学习类容,哈哈,又写了2 小时多,努力努力!!!