Android自定义控件——Path之贝塞尔曲线

可以看到,在经过 Path之基本操作、Path之贝塞尔曲线和 Path之完结篇后, Path中各类方法基本上都讲完了,表格中还没有讲解到到方法就是矩阵变换了,难道本篇终于要讲矩阵了? 非也,矩阵这一部分仍在后面单独讲解,本篇主要讲解 PathMeasure 这个类与 Path 的一些使用技巧。

PS:不要问我为什么不讲 PathEffect,因为这个方法在后面的Paint系列中。

先放一个图镇楼,省的下面无聊的内容把你们都吓跑了Σ( ̄。 ̄ノ)ノ


Path & PathMeasure

顾名思义,PathMeasure是一个用来测量Path的类,主要有以下方法:

构造方法

方法名 释义
PathMeasure() 创建一个空的PathMeasure
PathMeasure(Path path,boolean forceClosed) 创建 PathMeasure 并关联一个指定的Path(Path需要已经创建完成)。

公共方法

返回值 方法名 释义
void setPath(Path path,boolean forceClosed) 关联一个Path
boolean isClosed() 是否闭合
float getLength() 获取Path的长度
boolean nextContour() 跳转到下一个轮廓
boolean getSegment(float startD,float stopD,Path dst,boolean startWithMoveTo) 截取片段
boolean getPosTan(float distance,float[] pos,float[] tan) 获取指定长度的位置坐标及该点切线值
boolean getMatrix(float distance,Matrix matrix,int flags) 获取指定长度的位置坐标及该点Matrix

PathMeasure的方法也不多,接下来我们就逐一的讲解一下。


1.构造函数

构造函数有两个。

无参构造函数:

 PathMeasure ()

用这个构造函数可创建一个空的 PathMeasure,但是使用之前需要先调用 setPath 方法来与 Path 进行关联。被关联的 Path 必须是已经创建好的,如果关联之后 Path 内容进行了更改,则需要使用 setPath 方法重新关联。

有参构造函数:

  PathMeasure (Path path,boolean forceClosed)

用这个构造函数是创建一个 PathMeasure 并关联一个 Path, 其实和创建一个空的 PathMeasure 后调用 setPath 进行关联效果是一样的,同样,被关联的 Path 也必须是已经创建好的,如果关联之后 Path 内容进行了更改,则需要使用 setPath 方法重新关联。

该方法有两个参数,第一个参数自然就是被关联的 Path 了,第二个参数是用来确保 Path 闭合,如果设置为 true, 则不论之前Path是否闭合,都会自动闭合该 Path(如果Path可以闭合的话)。

在这里有两点需要明确:

  • 不论 forceClosed 设置为何种状态(true 或者 false), 都不会影响原有Path的状态,即 Path 与 PathMeasure 关联之后,之前的的 Path 不会有任何改变。
  • forceClosed 的设置状态可能会影响测量结果,如果 Path 未闭合但在与 PathMeasure 关联的时候设置 forceClosed 为 true 时,测量结果可能会比 Path 实际长度稍长一点,获取到到是该 Path 闭合时的状态。

下面我们用一个例子来验证一下:

canvas.translate(mViewWidth/2,mViewHeight/2);

Path path = new Path();

path.lineTo(0,200);
path.lineTo(200,0);

PathMeasure measure1 = new PathMeasure(path,false);
PathMeasure measure2 = new PathMeasure(path,true);

Log.e("TAG","forceClosed=false---->"+measure1.getLength());
Log.e("TAG","forceClosed=true----->"+measure2.getLength());

canvas.drawPath(path,mDeafultPaint);

log如下:

com.gcssloop.canvas E/TAG: forceClosed=false---->600.0
com.gcssloop.canvas E/TAG: forceClosed=true----->800.0

绘制在界面上的效果如下:

我们所创建的 Path 实际上是一个边长为 200 的正方形的三条边,通过上面的示例就能验证以上两个问题。

  • 我们将 Path 与两个的 PathMeasure 进行关联,并给 forceClosed 设置了不同的状态,之后绘制再绘制出来的 Path 没有任何变化,所以与 Path 与 PathMeasure进行关联并不会影响 Path 状态。
  • 我们可以看到,设置 forceClosed 为 true 的方法比设置为 false 的方法测量出来的长度要长一点,这是由于 Path 没有闭合的缘故,多出来的距离正是 Path 最后一个点与最开始一个点之间点距离。forceClosed 为 false 测量的是当前 Path 状态的长度, forceClosed 为 true,则不论Path是否闭合测量的都是 Path 的闭合长度。

2.setPath、 isClosed 和 getLength

这三个方法都如字面意思一样,非常简单,这里就简单是叙述一下,不再过多讲解。

setPath 是 PathMeasure 与 Path 关联的重要方法,效果和 构造函数 中两个参数的作用是一样的。

isClosed 用于判断 Path 是否闭合,但是如果你在关联 Path 的时候设置 forceClosed 为 true 的话,这个方法的返回值则一定为true。

getLength 用于获取 Path 的总长度,在之前的测试中已经用过了。

3.getSegment

getSegment 用于获取Path的一个片段,方法如下:

boolean getSegment (float startD,boolean startWithMoveTo)

方法各个参数释义:

参数 作用 备注
返回值(boolean) 判断截取是否成功 true 表示截取成功,结果存入dst中,false 截取失败,不会改变dst中内容
startD 开始截取位置距离 Path 起点的长度 取值范围: 0 <= startD < stopD <= Path总长度
stopD 结束截取位置距离 Path 起点的长度 取值范围: 0 <= startD < stopD <= Path总长度
dst 截取的 Path 将会添加到 dst 中 注意: 是添加,而不是替换
startWithMoveTo 起始点是否使用 moveTo 用于保证截取的 Path 第一个点位置不变
  • 如果 startD、stopD 的数值不在取值范围 [0,getLength] 内,或者 startD == stopD 则返回值为 false,不会改变 dst 内容。
  • 如果在安卓4.4或者之前的版本,在默认开启硬件加速的情况下,更改 dst 的内容后可能绘制会出现问题,请关闭硬件加速或者给 dst 添加一个单个操作,例如: dst.rLineTo(0,0)

我们先看看这个方法如何使用:

我们创建了一个 Path, 并在其中添加了一个矩形,现在我们想截取矩形中的一部分,就是下图中红色的部分。

矩形边长400dp,起始点在左上角,顺时针

代码:

canvas.translate(mViewWidth / 2,mViewHeight / 2);          // 平移坐标系

Path path = new Path();                                     // 创建Path并添加了一个矩形
path.addRect(-200,-200,200,Path.Direction.CW);

Path dst = new Path();                                      // 创建用于存储截取后内容的 Path

PathMeasure measure = new PathMeasure(path,false);         // 将 Path 与 PathMeasure 关联

// 截取一部分存入dst中,并使用 moveTo 保持截取得到的 Path 第一个点的位置不变
measure.getSegment(200,600,dst,true);                    

canvas.drawPath(dst,mDeafultPaint);                        // 绘制 dst

结果如下:

从上图可以看到我们成功到将需要到片段截取了出来,然而当 dst 中有内容时会怎样呢?

canvas.translate(mViewWidth / 2,Path.Direction.CW);

Path dst = new Path();                                      // 创建用于存储截取后内容的 Path
dst.lineTo(-300,-300);                                     // <--- 在 dst 中添加一条线段

PathMeasure measure = new PathMeasure(path,false);         // 将 Path 与 PathMeasure 关联

measure.getSegment(200,true);                   // 截取一部分 并使用 moveTo 保持截取得到的 Path 第一个点的位置不变

canvas.drawPath(dst,mDeafultPaint);                        // 绘制 Path

结果如下:

从上面的示例可以看到 dst 中的线段保留了下来,可以得到结论:被截取的 Path 片段会添加到 dst 中,而不是替换 dst 中到内容。

前面两个例子中 startWithMoveTo 均为 true, 如果设置为false会怎样呢?

canvas.translate(mViewWidth / 2,-300);                                     // 在 dst 中添加一条线段

PathMeasure measure = new PathMeasure(path,false);                   // <--- 截取一部分 不使用 startMoveTo,保持 dst 的连续性

canvas.drawPath(dst,mDeafultPaint);                        // 绘制 Path

结果如下:

从该示例我们又可以得到一条结论:如果 startWithMoveTo 为 true,则被截取出来到Path片段保持原状,如果 startWithMoveTo 为 false,则会将截取出来的 Path 片段的起始点移动到 dst 的最后一个点,以保证 dst 的连续性。

从而我们可以用以下规则来判断 startWithMoveTo 的取值:

取值 主要功用
true 保证截取得到的 Path 片段不会发生形变
false 保证存储截取片段的 Path(dst) 的连续性

4.nextContour

我们知道 Path 可以由多条曲线构成,但不论是 getLength,getSegment 或者是其它方法,都只会在其中第一条线段上运行,而这个 nextContour 就是用于跳转到下一条曲线到方法,如果跳转成功,则返回 true, 如果跳转失败,则返回 false。

如下,我们创建了一个 Path 并使其中包含了两个闭合的曲线,内部的边长是200,外面的边长是400,现在我们使用 PathMeasure 分别测量两条曲线的总长度。

代码:

canvas.translate(mViewWidth / 2,mViewHeight / 2);      // 平移坐标系

Path path = new Path();

path.addRect(-100,-100,100,Path.Direction.CW);  // 添加小矩形
path.addRect(-200,Path.Direction.CW);  // 添加大矩形

canvas.drawPath(path,mDeafultPaint);                    // 绘制 Path

PathMeasure measure = new PathMeasure(path,false);     // 将Path与PathMeasure关联

float len1 = measure.getLength();                       // 获得第一条路径的长度

measure.nextContour();                                  // 跳转到下一条路径

float len2 = measure.getLength();                       // 获得第二条路径的长度

Log.i("LEN","len1="+len1);                              // 输出两条路径的长度
Log.i("LEN","len2="+len2);

log输出结果:

com.gcssloop.canvas I/LEN: len1=800.0
com.gcssloop.canvas I/LEN: len2=1600.0

通过测试,我们可以得到以下内容:

  • 曲线的顺序与 Path 中添加的顺序有关。
  • getLength 获取到到是当前一条曲线分长度,而不是整个 Path 的长度。
  • getLength 等方法是针对当前的曲线(其它方法请自行验证)。

5.getPosTan

这个方法是用于得到路径上某一长度的位置以及该位置的正切值:

boolean getPosTan (float distance,float[] tan)

方法各个参数释义:

参数 作用 备注
返回值(boolean) 判断获取是否成功 true表示成功,数据会存入 pos 和 tan 中, false 表示失败,pos 和 tan 不会改变
distance 距离 Path 起点的长度 取值范围: 0 <= distance <= getLength
pos 该点的坐标值 当前点在画布上的位置,有两个数值,分别为x,y坐标。
tan 该点的正切值 当前点在曲线上的方向,使用 Math.atan2(tan[1],tan[0]) 获取到正切角的弧度值。

这个方法也不难理解,除了其中 tan 这个小编,这个东西是干什么的呢?

tan 是用来判断 Path 上趋势的,即在这个位置上曲线的走向,请看下图示例,注意箭头的方向:

点击这里下载箭头图片

可以看到 上图中箭头在沿着 Path 运动时,方向始终与 Path 走向保持一致,保持方向主要就是依靠 tan

下面我们来看看代码是如何实现的,首先我们需要定义几个必要的变量:

private float currentValue = 0;     // 用于纪录当前的位置,取值范围[0,1]映射Path的整个长度

private float[] pos;                // 当前点的实际位置
private float[] tan;                // 当前点的tangent值,用于计算图片所需旋转的角度
private Bitmap mBitmap;             // 箭头图片
private Matrix mMatrix;             // 矩阵,用于对图片进行一些操作

初始化这些变量(在构造函数中调用这个方法):

private void init(Context context) {
    pos = new float[2];
    tan = new float[2];
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 2;       // 缩放图片
    mBitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.arrow,options);
    mMatrix = new Matrix();
}

具体绘制:

canvas.translate(mViewWidth / 2,mViewHeight / 2);      // 平移坐标系

Path path = new Path();                                 // 创建 Path

path.addCircle(0,Path.Direction.CW);           // 添加一个圆形

PathMeasure measure = new PathMeasure(path,false);     // 创建 PathMeasure

currentValue += 0.005;                                  // 计算当前的位置在总长度上的比例[0,1]
if (currentValue >= 1) {
  currentValue = 0;
}

measure.getPosTan(measure.getLength() * currentValue,pos,tan);        // 获取当前位置的坐标以及趋势

mMatrix.reset();                                                        // 重置Matrix
float degrees = (float) (Math.atan2(tan[1],tan[0]) * 180.0 / Math.PI); // 计算图片旋转角度

mMatrix.postRotate(degrees,mBitmap.getWidth() / 2,mBitmap.getHeight() / 2);   // 旋转图片
mMatrix.postTranslate(pos[0] - mBitmap.getWidth() / 2,pos[1] - mBitmap.getHeight() / 2);   // 将图片绘制中心调整到与当前点重合

canvas.drawPath(path,mDeafultPaint);                                   // 绘制 Path
canvas.drawBitmap(mBitmap,mMatrix,mDeafultPaint);                     // 绘制箭头

invalidate();                                                           // 重绘页面

核心要点:

  • 通过 tan 得值计算出图片旋转的角度,tan 是 tangent 的缩写,即中学中常见的正切, 其中tan[0]是邻边边长,tan[1]是对边边长,而Math中 atan2 方法是根据正切是数值计算出该角度的大小,得到的单位是弧度(取值范围是 -pi 到 pi),所以上面又将弧度转为了角度。
  • 通过 Matrix 来设置图片对旋转角度和位移,这里使用的方法与前面讲解过对 canvas操作 有些类似,对于 Matrix 会在后面专一进行讲解,敬请期待。
  • 页面刷新,页面刷新此处是在 onDraw 里面调用了 invalidate 方法来保持界面不断刷新,但并不提倡这么做,正确对做法应该是使用 线程 或者 ValueAnimator 来控制界面的刷新,关于控制页面刷新这一部分会在后续的 动画部分 详细讲解,同样敬请期待。

关于tan这个参数有很多魔法师不理解,特此拉出来详述一下,tan 在数学中被称为正切,在直角三角形中,一个锐角的正切定义为它的对边(Opposite side)与邻边(Adjacent side)的比值(来自维基百科):

我们此处用 tan 来描述 Path 上某一点的切线方向,主要用了两个数值 tan[0] 和 tan[1] 来描述这个切线的方向(切线方向与x轴夹角) ,看上面公式可知 tan 既可以用 对边/邻边 来表述,也可以用 sin/cos 来表述,此处用两种理解方式均可以(注意下面等价关系):

tan[0] = cos = 邻边(单位圆x坐标)
tan[1] = sin = 对边(单位圆y坐标)

以 sin/cos理解:

在圆上最右侧点的切线方向向下(动图中小飞机朝向和切线朝向一致),切线角度为90度.
sin90 = 1,
cos90 = 0
tan[0] = cos = 0
tan[1] = sin = 1

以 对边/邻边 理解(单位圆上坐标):

按照这种理解方式需要借助一个单位圆,单位圆上任意一点到圆心到距离均为 1,以下图30度为例:

tan30 = 对边/邻边 = AB/OA = B点y坐标/B点x坐标

另外根据单位圆性质同样可以证得: sin30 = 对边/斜边 = AB/OB = AB = B点y坐标 (单位圆边上任意一点距离圆心距离均为1,故OB = 1) cos30 = 邻边/斜边 = OA/OB = OA = B点x坐标

化为通用公式即为: sin = 该角度在单位圆上对应点的y坐标 cos = 该角度在单位圆上对应点的x坐标

即 tan = sin/cos = y/x tan[0] = x tan[1] = y

另外注意,这个单位圆与小飞机路径没有半毛钱关系,例如上一个例子中的90度切线,不要在单位圆上找对应位置,要找对应角度的位置,90度对应的位置是(0,1),所以: tan[0] = x = 0 tan[1] = y = 1

其实绕来绕去全是等价的 (╯°Д°)╯︵ ┻━┻

PS: 使用 Math.atan2(tan[1],tan[0]) 将 tan 转化为角(单位为弧度)的时候要注意参数顺序。

6.getMatrix

这个方法是用于得到路径上某一长度的位置以及该位置的正切值的矩阵:

boolean getMatrix (float distance,int flags)

方法各个参数释义:

参数 作用 备注
返回值(boolean) 判断获取是否成功 true表示成功,数据会存入matrix中,false 失败,matrix内容不会改变
distance 距离 Path 起点的长度 取值范围: 0 <= distance <= getLength
matrix 根据 falgs 封装好的matrix 会根据 flags 的设置而存入不同的内容
flags 规定哪些内容会存入到matrix中 可选择 POSITION_MATRIX_FLAG(位置) ANGENT_MATRIX_FLAG(正切)

其实这个方法就相当于我们在前一个例子中封装 matrix 的过程由 getMatrix 替我们做了,我们可以直接得到一个封装好到 matrix,岂不快哉。

但是我们看到最后到 flags 选项可以选择 位置 或者 正切,如果我们两个选项都想选择怎么办?

如果两个选项都想选择,可以将两个选项之间用 | 连接起来,如下:

measure.getMatrix(distance,matrix,PathMeasure.TANGENT_MATRIX_FLAG | PathMeasure.POSITION_MATRIX_FLAG);

我们可以将上面都例子中 getPosTan 替换为 getMatrix, 看看是不是会显得简单很多:

具体绘制:

Path path = new Path();                                 // 创建 Path

path.addCircle(0,1]
if (currentValue >= 1) {
    currentValue = 0;
}

// 获取当前位置的坐标以及趋势的矩阵
measure.getMatrix(measure.getLength() * currentValue,PathMeasure.TANGENT_MATRIX_FLAG | PathMeasure.POSITION_MATRIX_FLAG);

mMatrix.preTranslate(-mBitmap.getWidth() / 2,-mBitmap.getHeight() / 2);   // <-- 将图片绘制中心调整到与当前点重合(注意:此处是前乘pre)

canvas.drawPath(path,mDeafultPaint);                     // 绘制箭头

invalidate();                                                           // 重绘页面

由于此处代码运行结果与上面一样,便不再贴图片了,请参照上面一个示例的效果图。

可以看到使用 getMatrix 方法的确可以节省一些代码,不过这里依旧需要注意一些内容:

  • matrix 的操作必须要在 getMatrix 之后进行,否则会被 getMatrix 重置而导致无效。
  • 2.矩阵对旋转角度默认为图片的左上角,我们此处需要使用 preTranslate 调整为图片中心。
  • 3.pre(矩阵前乘) 与 post(矩阵后乘) 的区别,此处请等待后续的文章或者自行搜索。

Path & SVG

我们知道,用Path可以创建出各种个样的图形,但如果图形过于复杂时,用代码写就不现实了,不仅麻烦,而且容易出错,所以在绘制复杂的图形时我们一般是将 SVG 图像转换为 Path。

你说什么是 SVG?

SVG 是一种矢量图,内部用的是 xml 格式化存储方式存储这操作和数据,你完全可以将 SVG 看作是 Path 的各项操作简化书写后的存储格式。

Path 和 SVG 结合通常能诞生出一些奇妙的东西,如下:

该图片来自这个开源库 ->PathView SVG 转 Path 的解析可以用这个库 -> AndroidSVG

限于篇幅以及本人精力,这一部分就暂不详解了,感兴趣的可以直接看源码,或者搜索一些相关的解析文章。


Path使用技巧

话说本篇文章的名字不是叫 玩出花样么?怎么只见前面啰啰嗦嗦的扯了一大堆不明所以的东西,花样在哪里?

前面的内容虽然啰嗦繁杂,但却是重中之重的基础,如果在修仙界,这叫根基,而下面讲述的内容的是招式,有了根基才能演化出千变万化的招式,而没有根基只学招式则是徒有其表,只能学一样会一样,很难适应千变万化的需求。

先放一个效果图,然后分析一下实现过程:

这是一个搜索的动效图,通过分析可以得到它应该有四种状态,分别如下:

状态 概述
初始状态 初始状态,没有任何动效,只显示一个搜索标志

原文地址:https://blog.csdn.net/weixin_61845324

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


更新Android SDK到3.0版本时,遇到Failed to rename directory E:\android\tools to E:\android\temp\ToolPackage.old01问题,导致无法更新,出现该问题的原因是由于3.0版本与较早的sdk版本之间文件结构有冲突,解决
Android 如何解决dialog弹出时无法捕捉Activity的back事件 在一些情况下,我们需要捕捉back键事件,然后在捕捉到的事件里写入我们需要进行的处理,通常可以采用下面三种办法捕捉到back事件: 1)重写onKeyDown或者onKeyUp方法 2)重写onBackPressed方
Android实现自定义带文字和图片的Button 在Android开发中经常会需要用到带文字和图片的button,下面来讲解一下常用的实现办法。一.用系统自带的Button实现 最简单的一种办法就是利用系统自带的Button来实现,这种方式代码量最小。在Button的属性中有一个是drawable
Android中的&quot;Unable to start activity ComponentInfo&quot;的错误 最近在做一款音乐播放器的时候,然后在调试的过程中发现一直报这个错误&quot;Unable to start activity ComponentInfo&quot;,从字面
Android 关于长按back键退出应用程序的实现最近在做一个Android上的应用,碰到一个问题就是如何实现长按back键退出应用程序。在网上查找了很多资料,发现几乎没有这样的实现,大部分在处理时是双击back键来退出应用程序。参考了一下双击back键退出应用程序的代码,网上主流的一种方法是下面
android自带的时间选择器只能精确到分,但是对于某些应用要求选择的时间精确到秒级,此时只有自定义去实现这样的时间选择器了。下面介绍一个可以精确到秒级的时间选择器。 先上效果图: 下面是工程目录: 这个控件我也是用的别人的,好像是一个老外写的,com.wheel中的WheelView是滑动控件的主
Android平台下利用zxing实现二维码开发 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing
Android ListView的item背景色设置以及item点击无响应等相关问题 在Android开发中,listview控件是非常常用的控件,在大多数情况下,大家都会改掉listview的item默认的外观,下面讲解以下在使用listview时最常见的几个问题。1.如何改变item的背景色和按
如何向Android模拟器中导入含有中文名称的文件在进行Android开发的时候,如果需要向Android模拟器中导入文件进行测试,通过DDMS下手动导入或者在命令行下通过adb push命令是无法导入含有中文文件名的文件的。后来发现借用其他工具可以向模拟器中导入中文名称的文件,这个工具就是Ultr
Windows 下搭建Android开发环境一.下载并安装JDK版本要求JDK1.6+,下载JDK成功后进行安装,安装好后进行环境变量的配置【我的电脑】-——&gt;【属性】——&gt;【高级】 ——&gt;【环境变量】——&gt;【系统变量】中点击【新建】:变量名:CLASSPATH变量值:……
如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题 在android中有时候可能要实现一个底部弹出菜单,此时可以考虑用PopupWindow来实现。下面就来介绍一下如何使用PopupWindow实现一个弹出窗。 主Activity代码:public void onCreat
解决Android中的ERROR: the user data image is used by another emulator. aborting的方法 今天调试代码的时候,突然出现这个错误,折腾了很久没有解决。最后在google上找到了大家给出的两种解决方案,下面给出这两种方法的链接博客:ht
AdvserView.java package com.earen.viewflipper; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory;
ImageView的scaleType的属性有好几种,分别是matrix(默认)、center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY。 |值|说明| |:--:|:--| |center|保持原图的大小,显示在ImageVie
文章浏览阅读8.8k次,点赞9次,收藏20次。本文操作环境:win10/Android studio 3.21.环境配置 在SDK Tools里选择 CMAKE/LLDB/NDK点击OK 安装这些插件. 2.创建CMakeLists.txt文件 在Project 目录下,右键app,点击新建File文件,命名为CMakeLists.txt点击OK,创建完毕! 3.配置文件 在CMa..._link c++ project with gradle
文章浏览阅读1.2w次,点赞15次,收藏69次。实现目的:由mainActivity界面跳转到otherActivity界面1.写好两个layout文件,activity_main.xml和otherxml.xmlactivity_main.xml&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;RelativeLayout ="http://schemas..._android studio 界面跳转
文章浏览阅读3.8w次。前言:最近在找Android上的全局代理软件来用,然后发现了这两款神作,都是外国的软件,而且都是开源的软件,因此把源码下载了下来,给有需要研究代理这方面的童鞋看看。不得不说,国外的开源精神十分浓,大家相互使用当前基础的开源软件,然后组合成一个更大更强的大开源软件。好吧,废话不多说,下面简单介绍一下这两款开源项目。一、ProxyDroid:ProxyDroid功能比较强大,用到的技术也比较多,源码也_proxydroid
文章浏览阅读2.5w次,点赞17次,收藏6次。创建项目后,运行项目时Gradle Build 窗口却显示错误:程序包R不存在通常情况下是不会出现这个错误的。我是怎么遇到这个错误的呢?第一次创建项目,company Domain我使用的是:aven.com,但是创建过程在卡在了Building 'Calculator' Gradle Project info这个过程中,于是我选择了“Cancel”第二次创建项目,我还是使用相同的项目名称和项目路_r不存在
文章浏览阅读8.9w次,点赞4次,收藏43次。前言:在Android上使用系统自带的代理,限制灰常大,仅支持系统自带的浏览器。这样像QQ、飞信、微博等这些单独的App都不能使用系统的代理。如何让所有软件都能正常代理呢?ProxyDroid这个软件能帮你解决!使用方法及步骤如下:一、推荐从Google Play下载ProxyDroid,目前最新版本是v2.6.6。二、对ProxyDroid进行配置(基本配置:) (1) Auto S_proxydroid使用教程
文章浏览阅读1.1w次,点赞4次,收藏17次。Android Studio提供了一个很实用的工具Android设备监视器(Android device monitor),该监视器中最常用的一个工具就是DDMS(Dalvik Debug Monitor Service),是 Android 开发环境中的Dalvik虚拟机调试监控服务。可以进行的操作有:为测试设备截屏,查看特定进程中正在运行的线程以及堆栈信息、Logcat、广播状态信息、模拟电话_安卓摄像头调试工具