public class BezierGestureTrackView extends View {

private Bitmap mBufferBitmap;
private Canvas mBufferCanvas;

public BezierGestureTrackView(Context context) {
super(context);
}
PointF pointF;

Paint paint;
Paint paint2;

Path p,path ;

@ColorInt public static final int YELLOW = 0xFFFFFF00;
@ColorInt
public static final int CYAN = 0xFF00FFFF;
public static final int c1 = 0xEF8A97;
public static final int c2 = 0xFBD2A8;

public BezierGestureTrackView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);//设置画笔的填充模式
paint.setStrokeJoin(Paint.Join.ROUND);//设置画笔图形接触时笔迹的形状
paint.setStrokeCap(Paint.Cap.ROUND);//设置画笔离开画板时笔迹的形状
paint.setStrokeWidth(8);//设置画笔粗细 6
paint.setAntiAlias(true);//设置抗锯齿
paint.setColor(Color.WHITE);
initPaint();
// BitmapFactory.decodeResource(getResources(), R.drawable.hbbg);
}

//新建两个SparseArray<Path>用来保存我们画出的Path对象,具体为什么之后会解释
//mActivePointers用来保存当前正在画的Path
SparseArray<Path> mActivePointers = new SparseArray<>();
//truePointers用来保存所有的Path,在onDraw()方法里面我们也是绘制这里的所有Path
SparseArray<Path> truePointers = new SparseArray<>();

//保存单个点
private int i=0;
private float[] a= new float[1000];

//重写onTouchEvent()方法
@Override
public boolean onTouchEvent(MotionEvent event) {

//获取当前DOWN或者UP的是手指的index
int curPointerIndex = event.getActionIndex();
//通过index获得当前手指的id
int curPointerId = event.getPointerId(curPointerIndex);
//获取当前正在发生的事件
int actionMasked = event.getActionMasked();

switch (actionMasked) {
//不管是第一个还是第N个手指落下,都执行以下方法:
case MotionEvent.ACTION_DOWN:

case MotionEvent.ACTION_POINTER_DOWN:
//新建一个PointF对象用来保存点的坐标
pointF = new PointF();
pointF.x = event.getX(curPointerIndex);
pointF.y = event.getY(curPointerIndex);
//每当有手指下落时,都新建一个Path,并移动到手指落下的点
Path p = new Path();
p.moveTo(pointF.x, pointF.y);
//将新建的path添加到mActivePointers中
mActivePointers.append(curPointerId, p);

//保存单个点位置

if (i<998){
a[i++]=event.getX(curPointerIndex);
a[i++]=event.getY(curPointerIndex);
}

break;

case MotionEvent.ACTION_MOVE:
//当有手指移动时,遍历mActivePointers,注意这里遍历的条件并不是mActivePointers.size(),而是event.getPointerCount()
//也就是只监控当前所有正在滑动的手指数,另外在MotionEvent.ACTION_UP事件中,抬起的手指已经从mActivePointers中删除了
for (int size = event.getPointerCount(), i = 0; i < size; i++) {
//获取mActivePointers中的每一个Path
path = mActivePointers.get(event.getPointerId(i));
if (path != null) {
//更新每一个Path将得到的点连线
path.lineTo(event.getX(i), event.getY(i));

}
}

break;
case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_POINTER_UP:
//当手指抬起时,代表已经绘制完毕,取得抬起的手指绘制图线实例,传入truePointers让Drow()绘制
path = mActivePointers.get(curPointerId);
truePointers.append(truePointers.size(), path);
//从mActivePointers中将抬起的手指删除
mActivePointers.remove(curPointerId);
break;

}
//重绘
invalidate();
return true;
}

private void initBuffer(){
mBufferBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mBufferCanvas = new Canvas(mBufferBitmap);
}

@Override
protected void onDraw(Canvas canvas) {
//canvas.drawColor(Color.BLACK);

// Bitmap srcBitmap= BitmapFactory.decodeResource(getResources(), R.drawable.hbbg);
// canvas.drawBitmap(srcBitmap,0f,0f,null);

//遍历mActivePointers,因为只有当手指抬起时Path才被加入truePointers,此时truePointers里面还没有保存当前正在绘制的图线
//如果没有遍历mActivePointers,则图线不会即时显示,只有在抬起手指的瞬间,图线才会一起显示
for (int size = mActivePointers.size(), i = 0; i < size; i++) {
Path path = mActivePointers.valueAt(i);
canvas.drawPath(path, paint);
}
//遍历truePointers,这里保存的是当前正在画的图线
for (int size = truePointers.size(), i = 0; i < size; i++) {
path = truePointers.valueAt(i);
//绘制truePointers里的所有Path
canvas.drawPath(path, paint);
}

if (pointF!=null){
//canvas.drawPoint(pointF.x, pointF.y,paint2);
canvas.drawPoints(a, paint2);

for (int j = 0; j < a.length; j++) {
Log.e("TAG","a:"+a[i]+"a的长度:"+a.length);
}
}

}
// public void clean(){
//// Canvas canvas = sh.lockCanvas();
////
////
//// if(canvas!=null){
//// Paint paint = new Paint();
//// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//// canvas.drawPaint(paint);
//////canvas.drawColor(Color.BLUE);
//// }
// Log.e("BezierGestureTrackView","CLEAN");
// }

public void clear() {

if (mBufferBitmap != null) {
if (mActivePointers!=null){
mActivePointers.clear();
}
if (truePointers != null) {
truePointers.clear();
}

mBufferBitmap.eraseColor(Color.TRANSPARENT);
invalidate();

}

}

private void initPaint() {
paint2 = new Paint();
//LinearGradient lg=new LinearGradient(0,0,100,100,Color.RED,Color.BLUE, Shader.TileMode.MIRROR); //参数一为渐变起初点坐标x位
LinearGradient lg=new LinearGradient(0,0,100,100,CYAN,YELLOW, Shader.TileMode.MIRROR); //参数一为渐变起初点坐标x位
paint2.setStyle(Paint.Style.STROKE);//设置画笔的填充模式
paint2.setStrokeJoin(Paint.Join.ROUND);//设置画笔图形接触时笔迹的形状
paint2.setStrokeCap(Paint.Cap.ROUND);//设置画笔离开画板时笔迹的形状
paint2.setStrokeWidth(45);//设置画笔粗细 50
paint2.setAntiAlias(true);//设置抗锯齿
paint2.setColor(Color.WHITE);//设置抗锯齿
paint2.setShader(lg);
}
}

自定义view,用来测试屏幕的更多相关文章

  1. 自定义View和ViewGroup

    为了扫除学习中的盲点,尽可能多的覆盖Android知识的边边角角,决定对自定义View做一个稍微全面一点的使用方法总结,在内容上面并没有什么独特的地方,其他大神们的博客上面基本上都有讲这方面的内容,如 ...

  2. Android 自定义View修炼-Android实现圆形、圆角和椭圆自定义图片View(使用BitmapShader图形渲染方法)

    一.概述 Android实现圆角矩形,圆形或者椭圆等图形,一般主要是个自定义View加上使用Xfermode实现的.实现圆角图片的方法其实不少,常见的就是利用Xfermode,Shader.本文直接继 ...

  3. 自定义View实现五子棋游戏

    成功的路上一点也不拥挤,因为坚持的人太少了. ---简书上看到的一句话 未来请假三天顺带加上十一回家结婚,不得不说真是太坑了,去年婚假还有10天,今年一下子缩水到了3天,只能赶着十一办事了. 最近还在 ...

  4. Android自定义View(一、初体验自定义TextView)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51454685 本文出自:[openXu的博客] 目录: 继承View重写onDraw方法 自 ...

  5. Android的自定义View及View的绘制流程

    目标:实现Android中的自定义View,为理清楚Android中的View绘制流程“铺路”. 想法很简单:从一个简单例子着手开始编写自定义View,对ViewGroup.View类中与绘制View ...

  6. 自定义View和ViewGroup(有这一篇就够了)

    为了扫除学习中的盲点,尽可能多的覆盖Android知识的边边角角,决定对自定义View做一个稍微全面一点的使用方法总结,在内容上面并没有什么独特的地方,其他大神们的博客上面基本上都有讲这方面的内容,如 ...

  7. 【朝花夕拾】Android自定义View篇之(五)Android事件分发机制(上)Touch三个重要方法的处理逻辑

    前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/10998855.html]谢谢! 在自定义View中,经常需要处理Android事件分发的问题, ...

  8. 【朝花夕拾】Android自定义View篇之(四)自定义View的三种实现方式及自定义属性使用介绍

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10979161.html],谢谢! 尽管Android系统提供了不少控件,但是有很多酷炫效果仍然 ...

  9. Android进阶之绘制-自定义View完全掌握(二)

    这是自定义View系列的第二篇博客,我们继续来学习关于自定义View的知识. 今天我们来实现一下广告条案例. 我们要实现的是这样的一个效果. 要想实现这样的效果,我们可以借助ViewPager控件,然 ...

  10. 【转载】自定义View,有这一篇就够了

    为了扫除学习中的忙点,尽可能多的覆盖Android知识的边边角角,决定对自定义View做一个稍微全面一点的使用方法总结,在内容上面并没有什么独特的地方,其他大神们博客上面基本上都有讲这方面的内容,如果 ...

随机推荐

  1. 直播报名|资深云原生架构师分享服务网格在腾讯 IT 业务的落地实践

    云原生在近几年的发展越来越火热,作为云上最佳实践而生的设计理念,也有了越来越多的实践案例,而一个个云原生案例的背后,是无声的巨大变革. 腾讯云主办首个云原生百科知识直播节目--<云原生正发声&g ...

  2. vue后退页面刷新数据和缓存数据

    我们在项目中经常使用this.$router.go(-1)  但是,有时我们需要把前一个页面的数据进行缓存,有时需要刷新数据,下面来记录一下怎么操作吧 首先:在vue项目中缓存页面我们能想到 keep ...

  3. js的基本数据类型和引用数据类型及深拷贝浅拷贝

    1.栈(stack)和堆(heap) stack为自动分配的内存空间,它由系统自动释放:而heap则是动态分配的内存,大小也不一定会自动释放 2.js数据类型分两种 (1)基本数据类型(值类型):Nu ...

  4. 01.Java面试都问啥?

    大家好,我是王有志.好久不见,不过这次没有休假,而是搞了个"大"工程,花了点时间自学Python,然后写了"玩具爬虫",爬某准网的面经数据,为来年的" ...

  5. Redis网络模型究竟有多强

    如果面试官问我:Redis为什么这么快? 我肯定会说:因为Redis是内存数据库!如果不是直接把数据放在内存里,甭管怎么优化数据结构.设计怎样的网络I/O模型,都不可能达到如今这般的执行效率. 但是这 ...

  6. 一文告诉你AVM中设置字体的方法

    ​ avm 是一种简便的多端开发框架,可以开发APP.小程序.H5.今天学习了一下使用 avm 开发 APP 怎么设置字体,下面将经验分享给大家. 所需步骤: 1.  将需要使用的字体文件放到代码包r ...

  7. 内网渗透-at&schtasks&impacket的使用

    内网机器结构 机器账号密码如下: 2008 r2 webserver 域内 web 服务器 本地管理员账号密码 : .\administraotr:admin!@#45 当前机器域用户密码 : god ...

  8. 孤独的照片【USACO 2021 December Contest Bronze】

    孤独的照片 Farmer John 最近购入了 \(N\) 头新的奶牛,每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一. 奶牛目前排成一排,Farmer John 想要为 ...

  9. elasticsearch实现简单的脚本排序(script sort)

    目录 1.背景 2.分析 3.构建数据 3.1 mapping 3.2 插入数据 4.实现 4.1 根据省升序排序 4.1.1 dsl 4.1.2 运行结果 4.2 湖北省排第一 4.2.1 dsl ...

  10. 题解P4474 王者之剑

    双倍经验 简要题意 给你一个 \(n\times m\) 的网格,数字在格子里,你需要取出一些格子,使得任意两个格子之间没有公共边,输出格子中的数字和的最大值. \(1 \le n,m \le 100 ...