仅通过改变控件属性的方式实现一些复杂的动画效果是比较有难度的,比如Nexus的开机动画就根本实现不了。这里将展示如何利用PathMeasure和SVG动画来实现复杂的动画效果。

初始化:

PathMeasure类似一个计算器,可以计算出指定路径的一些信息,比如路径总长、指定长度所对应的坐标点等。

构造方式一:
PathMeasure pathMeasure = new PathMeasure();
setPath(Path path, boolean forceClosed);
构造方式二:
PathMeasure(Path path, boolean forceClosed);
● forceClosed:表示Path最终是否需要闭合。forceClosed只对PathMeasure的测量结果有影响,例如一个折线段的Path,本身没有闭合,当forceClosed设置为true时,PathMeasure的计算就会包含最后一段闭合的路径,与原来的Path不同。

简单函数使用:

1.getLength()函数

public float getLength() // 获取当前计算的路径长度(不是整个路径)
protected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.translate(50, 50);Path path = new Path();path.moveTo(0, 0);path.lineTo(0, 100);path.lineTo(100, 100);path.lineTo(100, 0);PathMeasure measure1 = new PathMeasure(path, false);PathMeasure measure2 = new PathMeasure(path, true);Log.d("TAG", "forceClosed=false---->" + measure1.getLength());Log.d("TAG", "forceClosed=true----->" + measure2.getLength());Paint paint = new Paint();paint.setColor(Color.BLACK);paint.setStrokeWidth(8);paint.setStyle(Paint.Style.STROKE);canvas.drawPath(path, paint);
}

D/TAG:forceClosed=false---->300.0
D/TAG:forceClosed=true----->400.0

很明显,forceClosed=false时,则测量的是当前Path状态的长度;如果forceClosed=true,则不论Path是否闭合,测量的都是Path的闭合长度。

2.isClosed()函数

public boolean isClosed()

如果在关联Path的时候设置forceClosed为true,则这个函数的返回值一定为true。
3.nextContour()函数(contour:[ˈkɑːntʊr]外形; 轮廓)

Path可以由多条曲线构成,但不论是getLength()、getSegment()还是其他函数,都只会针对其中第一条线段进行计算。 而nextContour()就是用于跳转到下一条曲线的函数。如果跳转成功,则返回true;如果跳转失败,则返回false。

canvas.translate(150, 150);
Path path = new Path();
path.addRect(-50, -50, 50, 50, Path.Direction.CW);
path.addRect(-100, -100, 100, 100, Path.Direction.CW);
path.addRect(-120, -120, 120, 120, Path.Direction.CW);
canvas.drawPath(path, paint);PathMeasure measure = new PathMeasure(path, false);do {float len = measure.getLength();Log.d("TAG", "len=" + len);
} while (measure.nextContour());

通过do...while循环和measure.nextContour()函数结合,逐个枚举出Path中的所有曲线。

通过这个例子可以得出以下结论:

● 通过PathMeasure.nextContour()函数得到的曲线的顺序与Path中添加的顺序相同。

● getLength()等函数针对的都是当前的曲线,而不是整个Path。

getSegment()函数:

1.基本用法

boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)
● startD:(D:distance)开始【截取】位置【距离Path起始点】的长度。
● stopD:(D:distance)结束【截取】位置【距离Path起始点】的长度。
● dst:截取的Path将会被添加到dst中。注意是添加,而不是替换。
● startWithMoveTo:是否调用Path.moveTo()函数将路径的起始点改为新添加路径的起始点。即,如果draw了segment0,接着draw了segment1,如果startWithMoveTo=true,则路径的起始点为segment1的起始点;因为调用了start with moveTo()函数;startWithMoveTo=false路径的起始点不变,即为segment0的终点,保证路径连续。Begin the segment with a moveTo if startWithMoveTo is true.总之,true:各Path独立;false:各Path连续。
注:
如果startD、stopD数值不在取值范围[0, getLength]内,或者startD==stopD,则返回false,而且不会改变dst中的内容。
开启硬件加速功能后,绘图会出现问题,因此,在使用getSegment()函数时需要【禁用硬件加速】功能。

因为dst中保存的Path是被不断添加的,而不是每次被覆盖,设置为false,则新增的片段会从上一次Path终点开始计算,这样可以保存截取的Path片段数组连续起来。

示例一: 

canvas.translate(100, 100);
Path path = new Path();
path.addRect(-50, -50, 50, 50, Path.Direction.CW);
Path dst = new Path();
PathMeasure measure = new PathMeasure(path, false);
measure.getSegment(0, 150, dst, true);
canvas.drawPath(dst, paint);

通过measure.getSegment(0, 150, dst, true);截取长度为0~150。截取成功后,会把新的路径线段添加到dst路径中,最后画出dst路径:

结论一:路径截取是以路径的左上角为起始点开始的。

因为生成路径的方式指定的是Path.Direction.CW(顺时针方向),所以顺时针方向去截取。

结论二:路径的截取方向与路径的生成方向相同。

示例二:如果dst路径不为空

Path path = new Path();
path.addRect(-50, -50, 50, 50, Path.Direction.CW);
Path dst = new Path();
dst.lineTo(10, 100);
PathMeasure measure = new PathMeasure(path, false);
measure.getSegment(0, 150, dst, true);
canvas.drawPath(dst, paint);

  (dst中存在两条segment,都被draw出来了)

结论三:会将截取的Path片段添加到路径dst中,而不是替换dst中的内容。

示例三:如果startWithMoveTo参数为false

Path path = new Path();
path.addRect(-50, -50, 50, 50, Path.Direction.CW);
Path dst = new Path();
dst.lineTo(10, 100);
PathMeasure measure = new PathMeasure(path, false);
measure.getSegment(0, 150, dst, false);
canvas.drawPath(dst, paint);

startWithMoveTo的意思就是在添加新的路径前,是否调用Path.MoveTo()函数将路径的起始点改为新添加路径的起始点。如果设置为true,就会将路径起始点移动到新添加路径的起始点,就可以保持当前被添加路径的形状;而如果设置为false,则不会调用Path.moveTo()函数,会将路径起始点位置改为上一条路径的终点,从而保持连续性。新添加的路径除起始点位置被更改以外,其他路径点是不会被更改的。

 (drawPath()依次画添加进dst中的segment0、segment1、...segmentN)

结论四:如果startWithMoveTo为true,则被截取出来的Path片段保持原状;如果startWithMoveTo为false,则会将截取出来的Path片段的起始点移动到dst的最后一个点,以保证dst路径的连续性。

2.示例:路径加载动画

public GetSegmentView(Context context, AttributeSet attrs) {super(context, attrs);setLayerType(LAYER_TYPE_SOFTWARE, null);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);// 抗锯齿标志mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(4);mPaint.setColor(Color.BLACK);mDstPath = new Path();mCirclePath = new Path();mCirclePath.addCircle(100, 100, 50, Path.Direction.CW);mPathMeasure = new PathMeasure(mCirclePath, true);ValueAnimator animator = ValueAnimator.ofFloat(0, 1);animator.setRepeatCount(ValueAnimator.INFINITE);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {mCurAnimValue = (Float) animation.getAnimatedValue();invalidate();}});animator.setDuration(2000);animator.start();
}@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.WHITE);float stopD = mPathMeasure.getLength() * mCurAnimValue;mDestPath.reset();// 让性能更好!避免连续重画!mPathMeasure.getSegment(0, stopD, mDstPath, true);canvas.drawPath(mDstPath, mPaint);
}

由于每次调用getSegment()函数得到的路径都被添加到mDstPath中,所以要先调用mDstPath.reset()函数清空之前生成的路径。最后将本次生成的路径画出来即可。

  在生成动画时,始终是从0位置开始的。

@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.WHITE);float length = mPathMeasure.getLength();float stopD = length * mCurAnimValue;float startD = (float) (stopD - ((0.5 - Math.abs(mCurAnimValue - 0.5)) * length));mDstPath.reset();mPathMeasure.getSegment(startD, stopD, mDstPath, true);canvas.drawPath(mDstPath, mPaint);
}

在这里只改变了起始点的计算方法:

float startD = (float) (stop - ((0.5 - Math.abs(mCurAnimValue - 0.5)) * length));

根据效果描述,在进度为0~0.5时,路径的起始点都是0;进度为0.5~1时,路径的起始点逐渐靠近终点;当进度为1时,两点重合。

在进度小于0.5时,start=0;进度大于0.5时,start=2*mCurAnimaValue-1。

用if...else..语句来计算start也是可以的,比如:(但在代码中出现类似0.5这种纯数字,则不易阅读和维护)

float start = 0;
if (start >= 0.5) {start = 2 * mCurAnimValue -1;
}
...
mPathMeasure.getSegment(start, stop, mDstPath, true);

getPosTan()函数:

1.概述

getPosTan()函数用于得到路径上某一长度的位置以及该位置的正切值。

boolean getPosTan(float distance, float[] pos, float[] tan)
● distance:距离Path起始点的长度,取值范围为 {0, getLength}
● pos:该点的坐标值。当前点在画布上的位置有两个值,分别为x、y坐标。pos[0]表示x坐标,pos[1]表示y坐标
● tan:该点的正切值,也是个二维数组{cos, sin}

    

以上图中,B点坐标的正切值为\tan \frac{\prod }{6}=\frac{\sqrt{3}}{3},所以tan数组的返回值为(\frac{\sqrt{3}}{2},\frac{1}{2}) 。整个计算过程为:tan\alpha =\frac{y}{x}=\frac{1}{2}\div \frac{\sqrt{3}}{2}=\frac{\sqrt{3}}{3}

由于tan=sin/cos,所以tan数组值就是{cos, sin}。

在Math类中,有两个求反正切值的函数。

double atan(double d) // 参数是弧度值
double atan2(double y, double x) // 参数是(x,y)坐标值

由于tan={cos, sin},tan=sin/cos,所以弧度值=atan2(tan[1], tan[0])。

下图中有一个沿圆形旋转的箭头,而当箭头围绕圆形旋转时,应该实时地旋转箭头的转向,以使它的头与圆形连线吻合。比如,从X轴开始移动,移动了а角度后的情形如下图:

在移动а角度后,三角形要与圆形连线吻合,那箭头就要一直沿着连线的方向。∠a=∠c,正切夹角是多少度就需要旋转多少度。

结论:如果想让移动点旋转至与切线重合,则旋转角度要与正切角度相同。

public class GetPosTanView extends View {private Path mCirclePath, mDstPath;private Paint mPaint;private PathMeasure mPathMeasure;private Float mCurAnimValue;private Bitmap mArrawBmp;public GetPosTanView(Context context, AttributeSet attrs) {super(context, attrs);setLayerType(LAYER_TYPE_SOFTWARE, null);mArrawBmp = BitmapFactory.decodeResource(getResources(), R.drawable.arraw);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(4);mPaint.setColor(Color.BLACK);mDstPath = new Path();mCirclePath = new Path();mCirclePath.addCircle(100, 100, 50, Path.Direction.CW);mPathMeasure = new PathMeasure(mCirclePath, true);ValueAnimator animator = ValueAnimator.ofFloat(0, 1);animator.setRepeatCount(ValueAnimator.INFINITE);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mCurAnimValue = (Float) animation.getAnimatedValue();invalidate();}});animator.setDuration(2000);animator.start();
}

在将图片加载到内存中之后,在每次重绘时,先将图片旋转,然后再绘制到画布上。

private float[] pos = new float[2];
private float[] tan = new float[2];
@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.WHITE);float stopD = mPathMeasure.getLength() * mCurAnimValue;mDestPath.reset();mPathMeasure.getSegment(0, stopD, mDstPath, true);canvas.drawPath(mDstPath, mPaint);mPathMeasure.getPosTan(stopD, pos, tan);float degrees = (float) (Math.atan2 (tan[1], tan[0]) * 180.0 / Math.PI);Matrix matrix = new Matrix() ;matrix.postRotate(degrees, mArrawBmp.getwidth() / 2, mArrawBmp.getHeight() / 2);matrix.postTranslate(pos[0], Pos[1]);canvas.drawBitmap(mArrawBmp, matrix, mPaint);
}

需要注意的是:

(1)pos、tan数组在使用时必须使用new关键词分配存储空间,而PathMeasure.getPosTan()函数只会向数组中的元素赋值。如果事先没有分配空间,则getPosTan()函数将不会获取成功。

(2)通过Math.atan2(tan[1], tan[0])函数得到的是弧度值而不是角度值,所以要通过(Math.atan2(tan[1],tan[0])*180.0/Math.PI)将弧度值转换为角度值。

先利用matrix.postRotate()函数将图片围绕中心点旋转指定角度,以便和切线重合。

然后利用matrix.postTranslate()函数将图片从默认的(0,0)移动到当前路径的最前端。

最后将图片绘制到画布上。

从效果图中可以看出,虽然箭头随着路径轨迹移动,但有点偏差。

    

在移动图片时,是以图片的左上角为起始点开始移动的,所以原来的(0,0)点移动(pos[0],pos[1])距离后,图片的左上角在(pos[0],pos[1])位置上。这说明我们移动过头了,少移动半个图片大小就可以了。

将移动图片的代码加以改造,少移动半个图片大小。

Matrix matrix = new Matrix();
matrix.postRotate(degrees, mArrawBmp.getwidth() / 2, mArrawBmp.getHeight() / 2);
matrix.postTranslate(pos[0] - mArrawBmp.getwidth() / 2,pos[1] - mArrawBmp.getHeight() / 2);
canvas.drawBitmap(mArrawBmp, matrix, mPaint);

getMatrix()函数:

这个函数用于得到路径上某一长度的位置以及该位置的正切值的矩阵。

boolean getMatrix(float distance, Matrix matrix, int flags)
● distance:距离Path起始点的长度
● matrix:根据flags封装好的matrix会根据flags的设置而存入不同的内容
● flags:用于指定哪些内容会存入matrix中。flags的值有两个:PathMeasure.POSITION_MATRIX_FLAG:表示获取位置信息;PathMeasure.TANGENT_MATRIX_FLAG:表示获取切边信息,使得图片按Path旋转。可以只指定一个,也可以使用“|”(或运算符)同时指定。

很明显,getMatrix()函数只是PathMeasure.getPosTan()函数的另一种实现而已。getPosTan()函数把获取到的位置和切边信息分别保存在pos和tan数组中;而getMatrix()函数则直接将其保存到matrix数组中。

下面使用getMatrix()函数代替getPosTan()函数实现箭头加载动画。

protected void onDraw(Canvas canvas) {super.onDraw(canvas);// 绘制路径加载动画,与“路径加载动画”示例相同,在此省略...// 计算方位角Matrix matrix = new Matrix();mPathMeasure.getMatrix(stopD, matrix, PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.TANGENT_MATRIX_FLAG);matrix.preTranslate(-mArrawBmp.getWidth()/2, -mArrawBmp.getHeight()/2);canvas.drawBitmap(mArrawBmp, matrix, mPaint);
}

这里通过getMatrix()函数将获取的位置信息和切边信息保存到matrix中。由于matrix中已经保存了当前的位置信息,所以我们只需要再将图片移动半个图片大小就可以了,所以使用matrix.preTranslate(-mArrawBmp.getWidth()/2, -mArrawBmp.getHeight()/2);移动半个图片大小。至于这里为什么使用preTranslate()函数移动,而上面代码用postTranslate()函数移动,在后面Matrix章节会具体介绍。

示例:支付宝支付成功动画

从这张图中可以看出在圆心(mCenterX,mCenterY)的基础上,如何根据圆形半径mRadius计算出对钩各个点的过程。

private int mCenterX = mCenterY = 100;
private int mRadius = 50;
public AliPayView(Context context, AttributeSet attrs) {super(context, attrs);setLayerType(LAYER_TYPE_SOFTWARE, null);// mPaint初始化与“路径加载动画”示例相同,在此省略...mDstPath = new Path();mCirclePath = new Path();mCirclePath.addCircle(mCenterX, mCenterY, mRadius, Path.Direction.CW);mCirclePath.moveTo(mCenterX-mRadius/2, mCenterY);mCirclePath.lineTo(mCenterX, mCenterY+mRadius/2);mCirclePath.lineTo(mCenterX+mRadius/2, mCenterY-mRadius/3);mPathMeasure = new PathMeasure(mCirclePath, false);ValueAnimator animator = ValueAnimator.ofFloat(0, 2);animator.addUpdateListener(new AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mCurAnimValue = (Float) animation.getAnimatedValue();invalidate();}});animator.setDuration(4000);animator.start();
}

相比“路径加载动画”示例,这里主要有两点改动:第一,在构造mCirclePath时,除添加圆形路径以外,还添加了一条对钩路径;第二,在构造ValueAnimator动画时,构造的是ofFloat(0, 2)之间的动画,这是因为我们有两条路径,0~1之间时画第一条路径,在1~2之间时画第二条路径。

protected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.WHITE);if (mCurAnimValue < 1) {float stopD = mPathMeasure.getLength() * mCurAnimValue;mPathMeasure.getSegment(0, stopD, mDstPath, true);} else if (mCurAnimValue == 1) {mPathMeasure.getSegment(0, mPathMeasure.getLength(), mDstPath, true);mPathMeasure.nextContour();} else {float stopD = mPathMeasure.getLength() * (mCurAnimValue -1);mPathMeasure.getSegment(0, stopD, mDstPath, true);}canvas.drawPath(mDstPath, mPaint);
}

注意动画细节,可以理解为一条路径有它的头部和尾部,是先慢慢出现半圈,接着尾部开始动起来,直到慢慢追上头部,最终合二为一。

在绘图时,当mCurAnimValue<1时,画外圈的圆形;当mCurAnimYalue=1时,说明圆已经画完,此时,先利用mPathMeasure.getSegment()函数将圆画完,然后调用mPathMeasure.nextContour()函数将路径转到对钩路径上;当mCurAnimValue>1时,说明已经在对钩路径上了。

如果在mCurAnimValue==1时,添加如下代码进去:

mCount = 1;
mPathMeasure.getSegment(0, mPathMeasure.getLength(), mDstPath, true);float len = mPathMeasure.getLength();while(mPathMeasure.nextContour()){mCount++;}Log.d("TAG", "len=" + len + ",count=" + mCount);
D/TAG: len=313.65173,2
D/TAG: len=83.37617,2

由日志可以看出,有且仅有两条路径:

用数学计算:圆周长=2 * π * 50 = 314.1592,对勾总长=√((25+50/3)^2 + 25^2) ) = 83.9466。与Log打印出的数值有点偏差。这是可以理解的,毕竟数学计算与像素拼成的圆本来就不一模一样。

❶在mCirclePath这一个Path中添加了两条路径,为什么就是两条segment的呢?

因为mPathMeasure = new PathMeasure(mCirclePath, false);  forceClosed = false,即是两条独立的路径。

❷以上代码中肯定是多次调用mPathMeasure.getSegment(0, stopD, mDstPath, true);为什么nextContour()没有取出添加的数个片段路径?

Path可以由多条曲线构成,但不论是getLength()、getSegment()还是其他函数,都只会针对其中第一条线段进行计算。 而nextContour()就是用于跳转到下一条曲线的函数。所以mPathMeasure.nextContour()跳转到的曲线与mDstPath中添加的曲线无关。mPathMeasure中有两条路径,mDstPath中有数个片段路径。


出于便于理解的考虑,本节的例子中使用了很多纯数字,这是不可取的。因为固定的数字是无法适应多变的需求的,这里我们只有两条路径,如果要在对钩上面再加一条心形路径该怎么办呢?这里的代码就得重写,而不是只添加心形路径就可以解决的。而这里的关键在于如何得知有几条路径,在得知有几条路径后 ,就可以逐个对其枚举作画。所以,我们可以提供一个接口,在外部设置Path实例,并且指定当前Path实例中的路径条数;或者,我们可以克隆一个Path实例,使用PathMeasure.nextContour()函数进行遍历,当该函数返回false时,则表明遍历结束。解决方法有很多。

二、SVG动画

概述:

SVG的全称是Scalable Vector Graphics(可缩放失量图形),由此可知SVG是失量图,而且是专门用于网络的失量图形标准。失量图由一个个点组成,经过数学计算利用直线和曲线绘制而成,无论如何放大,都不会出现马赛克现象,Illustrator就是常用的失量图绘图软件。

SVG与Bitmap相比有哪些好处:

● SVG使用XML格式定义图形,可被非常多的工具读取和修改。

● SVG由点来存储,由计算机根据点信息绘图,不会失真,无须根据分辨率适配多套图标。

● SVG的占用空间明显比Bitmap小。比如一张500px×500px的图像,转成SVG后占用的空间大小是20KB,而PNG图片则需要732KB的空间。

● SVG可以转换为Path路径,与Path动画相结合,可以形成更丰富的动画。

Google在Android 5.0中增加了对SVG图形的支持 。对于5.0以下的机型,可以通过引入 com.android.suppor:appcompat-v7:23.4.0及以上版本进行支持。

SVG这种图像格式在HTML中早就被广泛使用,比如下面这段SVG代码:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"><rect x="25" y="25" height="200" fill="lime" stroke-width="4" stroke="pink" /><circle cx="125" cy="125" r="75" fill="orange" /><polyline points="50,150 50,200 200,200 200,100" stroke="red" stroke-width="4" fill="none" /><line x1="50" y1="50" x2="200" y2="200" stroke="blue" stroke-width="4" />
</svg>

vector标签与图像显示:

<vector xmlna:android="http://schemas.android.com/apk/res/android"android:width="200dp"android:height="100dp"android:viewportWidth="100"android:viewportHeight="50"><pathandroid:name="bar"android:pathDate="M50,25 L100,25"android:strokeWidth="2"android:strokeColor="@android:color/darker_gray"/>
</vector>

● width、height:表示该SVG图形的具体大小。

● viewportWidth、viewportHeight:表示SVG图形划分的比例。指将画布的宽、高分为多少个点。Path中的点坐标都是以viewportWidth与viewportHeight的点数为坐标的,而不是dp值。

比如,将宽度200dp分为100个点,高度100dp分为50个点。<path>中M表示moveTo,L表示lineTo。所以,这里代表从点(50,25)到点(100,25)画了一条线段。这里的坐标就是以viewportWidth和viewportHeight所指定的点为单位的,即一个点有2dp。在高度上点25是中间点,在宽度上点50是中间点,而点100则表示宽度的结束位置。

很明显,<vector>标签指定的是画布大小,而<path>标签则指定的是路径内容。

1.path标签

1)常用属性

• android:name:声明一个标记,类似于ID,便于对其做动画的时候顺利地找到该节点。
• android:pathData:对SVG矢量图的描述。
• android:strokeWidth:画笔的宽度。
• android:fillColor:填充颜色。
• android:fillAlpha:填充颜色的透明度。
• android:strokeColor:描边颜色。
• android:strokeWidth:描边宽度。
• android:strokeAlpha:描边透明度。
• android:strokeLineJoin:用于指定折线拐角形状,取值有miter(结合处为锐角)、round(结合处为圆弧)、bevel(结合处为直线)。
• android:strokeLineCap:画出线条的终点的形状(线帽),取值有butt(无线帽)、round(圆形线帽)、square(方形线帽)。
• android:strokeMiterLimit:设置斜角的上限。注意:当strokeLineJoin设置为“miter”,即绘制的两条线 段以锐角相交的时候,所得的斜面可能相当长。当斜面太长时,就会变得不协调。strokeMiterLimit属性为斜面的长度设置了一个上限。这个属性表示斜面长度和线条长度的比值,默认值是 10,意味着一个斜面的长度不应该超过线条宽度的10倍。如果斜面达到这个长度,它就变成斜角了。当strokeLineJoin为“round”或“bevel”的时候,这个属性无效。其中,android:strokeLineJoin的效果对应于setStrokeJoin(Paint.Join join)函数,
android:strokeLineCap的效果对应于Paint.setStrokeCap(Paint.Cap cap)函数,
各个取值的效果在后面讲解Paint类时会具体讲述。

2)android:trimPathStart属性(trim:[trɪm]:修剪;切去;割掉;剪下;除去)

该属性用于指定路径从哪里开始,取值0~1,表示路径开始位置的百分比。取值0时,从头部开始;取值1时,整条路径不可见。

为了展示效果,灰色部分代表的是被删除的路径部分,而黑色部分是显示出来的路径。

3)android:trimPathEnd属性

该属性用于指定路径从哪里结束,取值0~1,表示路径结束位置的百分比。取值0时,从开始位置就已经结束;取值1时,正常结束。

4)android:trimPathOffset属性

该属性用于指定结果路径的位移位置,取值0~1。取值0时,不进行位移;取值1时,位移整条路径的长度。

    当trimPathOffset=1时,位移整条路径的长度,被截取的路径又回到原来的位置。

5)android:pathData属性

在<path>标签中,主要通过pathData属性来指定SVG图像的显示内容。

● M = moveTo(M X,Y):将画笔移动到指定的坐标位置。
● L = lineTo(L X,Y):画直线到指定的坐标位置。
● H = horizontal lintto(H X):画水平线到指定的X坐标位置。
● V = vertical lineto(V Y):画垂直线到指定的Y坐标位置。
● C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三阶贝济埃曲线。
● S = smooth curveto(S X2,Y2,ENDX,ENDY):三阶贝济埃曲线。这里传值相比C指令少了X1,Y1坐标,这是因为S指令会将上一条指令的终点作为这条指令的起始点。
● Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二阶贝济埃曲线。
● T = smooth quadratic Belzier curveto(T ENDX,ENDY):映射前面路径后的终点。
● A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧线。
● Z = closepath():关闭路径
A指令用来绘制一条弧线,且允许弧线不闭合。A指令各参数含义如下:
● RX,RY:指所有椭圆的半轴大小。
● XROTATION:指椭圆的X轴和水平方向顺时针方向的夹角,可以相像成一个水平的椭圆绕中心点顺时针旋转XROTAION角度。
● FLAG1:只有两个值,1表示大角度弧度,0表示小角度弧度。
● FLAG2:只有两个值,确定从起始点到终点的方向,1表示顺时针,0表示逆时针。
● X,Y:为终点坐标
有以下几点要注意:
● 坐标轴心(0,0)为中心,X轴水平向右,Y轴垂直向下。
● 所有指令大小写均可。大写表示绝对定位,参照全局坐标系;小写表示相对定位,参照父容器坐标系。
● 指令和数据间的空格可以省略。
● 同一指令出现多次可以只用一个。

2.group标签

path标签用于定义可绘图的路径,而group标签则用于定义一系列路径或者将path标签分组。在静态显示图像时,是单纯使用一个path标签实现还是使用一组path标签实现没有什么实质性的区别,其主要应用在动画中。在动画中,我们可以指定每个path路径做特定的动画,通过group标签则可以将原本由一个path路径实现的内容分为多个path路径来实现,每个path路径可以指定特定的动画,这样一来,效果显示就丰富多彩了。

group标签的使用非常随意,在vector标签下可以同时有一个或多个group标签和path标签,比如下图所示的用法是允许的。

group标签具有以下常用属性:

● android:name:组的名字,用于与动画相关联。
● android:rotation:指定该组图像的旋转度数。
● android:pivotX:定义缩放和旋转该组时的X参考点。该值是相对于vector的viewport值来指定的。
● android:pivotY:定义缩放和旋转该组时的Y参考点。该值是相对于vector的viewport值来指定的。
● android:scaleX:指定该组X轴缩放大小。
● android:scaleY:指定该组Y轴缩放大小。
● android:translateX:指定该组沿X轴平移的距离。
● android:translateY:指定该组沿Y轴平移的距离。
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="200dp"android:height="100dp"android:viewportWidth="100"android:viewportHeight="50"><groupandroid:rotation="90"android:pivotX="50"android:pivotY="25"><pathandroid:name="bar"android:pathData="M50,23 L100,23"android:strokeWidth="2"android:strokeColor="@android:color/darker_gray"/></group>
</vector>

以上例子是将path的水平路径围绕画面中心点旋转90°:

3.制作SVG图像

可以使用Illustrator,或在线SVG图像制作工具:Method Draw,或通过SVG源文件下载网站下载后进行编辑。

有很多Iconfont开源网站,比如国内的阿里巴巴失量图库:http://www.iconfont.cn

4.在Android中引入SVG图像

在Android中是不支持SVG图像解析的,我们必须将SVG图像转换为vector标签描述,有两种方法。

方法一:在线转换

将SVG图像,直接拖入在线转换网站Android SVG to VectorDrawable

方法二:通过Android Studio引入

  

可选择本地SVG文件、可选择IDE自带的SVG文件,可调节大小、透明度。

Enable auto mirroring for RTL layout:中国的习惯是从左向右,当出现从右向左显示时,通过RTL可以水平镜像翻转图标。

5.示例

1)引入兼容包

android {defaultConfig {vectorDrawables.useSupportLibrary = true}
}

2)生成Vector图像 

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="200dp"android:height="100dp"android:viewportWidth="100"android:viewportHeight="50"><pathandroid:name="bar"android:pathData="M50,25 L100,25"android:strokeWidth="2"android:strokeColor="@android:color/darker_gray"/>
</vector>

3)在ImageView、ImageButton中使用 

<ImageViewandroid:id="@+id/iv"android:layout_width="wrap_content"android:layout_height="wrap_content"app:srcCompat="@drawable/svg_line"/>
ImageView iv = (ImageView) findViewById(R.id.iv);
iv.setImageResource(R.drawable.svg_line);

4)在Button、RadioButton中使用

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/svg_line" android:state_pressed="true"/><item android:drawable="@drawable/svg_line"/>
</selector>
<Buttonandroid:id="@+id/btn"android:layout_width="70dp"android:layout_height="70dp"android:background="@drawable/selector_svg_line"/>

然而到这里并不能直接运行,因为兼容包还存在一个缺陷,我们需要把下面这段代码放在Activity前面。

public class MainActivity extends AppCompatActivity {static {AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);}@Overrideprotected void onCreate(Bundle savedInstanceState) {...}
}

动态Vector:

动态Vector所实现的动态SVG效果才是SVG图像在Android应用中的精髓。

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="200dp"android:height="100dp"android:viewportWidth="100"android:viewportHeight="50"><pathandroid:name="bar"android:pathData="M50,25 L100,25"android:strokeWidth="2"android:strokeColor="@android:color/darker_gray"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<objectAnimatorxmlns:android="http://schemas.android.com/apk/res/android"android:propertyName="trimPathStart"android:valueFrom="0"android:valueTo="1"android:duration="2000" />
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"android:drawable="@drawable/svg_line"><targetandroid:name="bar"android:animation="@animator/anim_trim_start"/>
</animated-vector>

首先通过<animated-vector>标签的android:drawable属性指定Vector图像;然后通过<target>标签将路径与动画关联,<target>标签的android:name属性就是指定的<path>标签的name,它与Vector文件中的<path>标签相对应,两者必须相同,代表的就是对哪个<path>标签做动画;最后通过android:animation属性来指定这个<path>标签所对应的动画。在<animated-vector>标签中可以有很多个<target>标签,每个target标签可以将一个Path与Animator相关联。

最后在代码中使用:

ImageView imgView = (ImageView) findViewById(R.id.iv);
AnimatedVectorDrawableCompat animatedVectorDrawableCompat = AnimatedVectorDrawableCompat.create(MainActivity.this, R.drawable.line_animated_vector);
imgView.setImageDrawable(animatedVectorDrawableCompat);
((Animatable) imgView.getDrawable()).start();

示例:输入搜索动画

1.准备SVG图像(drawable/vector_search_bar.xml):

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="150dp"android:height="24dp"android:viewportWidth="150"android:viewportHeight="24"><!--搜索图形--><pathandroid:name="search"android:pathData="M141,17 A9,9 0 1,1 142,16 L149,23"android:strokeWidth="2"android:strokeColor="@android:color/darker_gray"/><!--底部横线--><pathandroid:name="bar"android:trimPathStart="1"android:pathData="M0,23 L149,23"android:strokeWidth="2"android:strokeColor="@android:color/darker_gray"/>
</vector>

2.准备动画(animator/anim_bar_trim_start.xml):

对于底部横线而言,从左至右逐渐减小,所以是对起始点位置的操作。(animator/anim_search_trim_start.xml)

<?xml version="1.0" encoding="utf-8"?>
<objectAnimatorxmlns:android="http://schemas.android.com/apk/res/android"android:propertyName="trimPathStart"android:valueFrom="0"android:valueTo="1"android:valueType="floatType"android:duration="500" />

对于搜索图形而言,则从无到有显示出来,所以是对终点位置的操作。(animator/anim_search_trim_end.xml)

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="500"android:propertyName="trimPathEnd"android:valueFrom="0"android:valueTo="1"android:valueType="floatType" />

通过<animated-vector>标签将SVG图像与动画关联起来。(drawable/animated_vector_search.xml)

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"android:drawable="@drawable/vector_search_bar" ><targetandroid:animation="@animator/anim_search_trim_end"android:name="search"/><targetandroid:animation="@animator/anim_bar_trim_start"android:name="bar"/>
</animated-vector>

3.布局与开始动画

<?xml version="1.0" encoding="utf-8"?>
<FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_marginTop="20dp"android:layout_marginLeft="20dp"android:layout_width="match_parent"android:layout_height="match_parent"><EditTextandroid:id="@+id/edit"android:hint="点击输入"android:layout_width="150dp"android:layout_height="24dp"android:background="@null"/><ImageViewandroid:id="@+id/anim_img"android:layout_width="150dp"android:layout_height="24dp"/>
</FrameLayout>
public class SearchEditActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.svg_edit_search_activity);final ImageView imageView = (ImageView) findViewById(R.id.anim_img);//将焦点放在ImageView上imageView.setFocusable(true);imageView.setFocusableInTouchMode(true);imageView.requestFocus();imageView.requestFocusFromTouch();EditText  editText = (EditText)findViewById(R.id.edit);//当EditText获得焦点时开始动画editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {if (hasFocus) {AnimatedVectorDrawableCompat animatedVectorDrawableCompat = AnimatedVectorDrawableCompat.create(SearchEditActivity.this, R.drawable.animated_vecotr_search);imageView.setImageDrawable(animatedVectorDrawableCompat);((Animatable) imageView.getDrawable()).start();}}});}
}

由于EditText会默认获得焦点,所以我们首先需要将焦点放在ImageView上,然后当用户点击EditText的时候,EditText获得焦点,此时开始动画。

这里我们产生讲解了如何通过兼容包来实现在Android2.1以上平台中显示SVG图像与使用SVG动画的问题。相比5.0以上的原生SVG支持,兼容包对以下内容是不支持的。

● Path Morphing:路径变换动画,在Anroid pre-L版本下是无法使用的。

● Path Interpolator:路径插值器,在Android pre-L版本下只能使用系统的插值器,不能自定义插值器。

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 十进制数转换为二进制数的除2取余法和乘2取整法的依据

    ...

    2024/4/15 4:26:12
  2. gson与fastjson使用上的区别

    gson 转换时 如果没有指定字段属性 只是使用Object 接收 Integer类型数据会默认转换成 Double 可以使用fastjson 就没有这个问题了Map<String, BinlogFieldEntity> binlogMap = gson.fromJson(binlogObj,new TypeToken<HashMap<String,BinlogFieldEntity>{}.ge…...

    2024/4/15 4:26:10
  3. 微服务核心架构梳理

    什么是微服务微服务之父Martin Fowler,对微服务大概的概述如下:就目前而言,对于微服务业界并没有一个统一的、标准的定义(While there is no precise definition of this architectural style ) 。但通常而言,微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一…...

    2024/5/7 16:50:55
  4. Codeforces Round #648 (Div. 2) Jun/07/2020 22:35UTC+8

    Codeforces Round #648 Div. 2 Jun/07/2020 22:35UTC+8B. Trouble SortC. Rotation MatchingD. Solve The MazeE. Maximum Subsequence ValueF. Swaps Again(思维) 比赛链接 https://codeforces.com/contest/1365 比赛记录 https://blog.csdn.net/cheng__yu_/article/details…...

    2024/5/7 12:47:05
  5. 清理分区注意事项

    1、检查要处理表是否存在全局索引select * from user_indexes t where table_name =xxxxxxx and t.PARTITIONED=NO2、若存在,以下两种方法(1)删除分区或者truncate分区后要更新全局索引(此操作会产生排它锁,导致表不可用,同时也会加重服务器负载)alter table xxxxxxx dr…...

    2024/5/7 23:14:38
  6. 猎鹰与龙飞船基于 Linux,采用 C++、Chromium 与 JS 开发

    最近两天科技界最重大的事件莫过于马斯克的 SpaceX 成功实现了猎鹰 9 号(Falcon 9)带着龙飞船(Crew Dragon)成功发射,并使飞船与国际空间站对接,将 NASA 两名宇航员送上了轨道前哨。背后关于 Falcon 9 与 Crew Dragon 使用的计算机和软件等信息也引起了开发者的关注。多年…...

    2024/5/7 20:49:50
  7. GStreamer官方入门课程3:面向复杂媒体流,教你如何动态构建 GStreamer 复杂管道

    1. 目标 本教程展示了使用GStreamer所需的其他基本概念,这些概念允许在信息可用时“动态”构建管道,而不是在应用程序的开头定义单片管道。 在本教程之后,您将拥有开始播放教程所必需的知识。这里回顾的要点是:如何在链接元素时获得更好的控制。 如何得到有趣事件的通知以便…...

    2024/4/20 9:20:15
  8. 股票札记

    6.9利用好尾盘来对仓位进行调整。尾盘效应特别是最后30分钟大盘的走向基本不出意外的决定次日高开或者低开。 MACD二次翻红捕捉起涨点。MACD连续二次翻红,是指MACD第一次出现红柱后,还没有等红柱缩没变绿便再次放大其红柱,这是利用MACD选强势股的关键,也是介入的最佳买点。…...

    2024/4/18 20:02:53
  9. 2020自我面试题

    1.java基础 1. String,StringBuffer与StringBuilder的区别速度上StringBuilder>StringBuffer>String,string final所以不可变不可继承不可实现StringBuffer synchronized 线程安全,所以速度慢 2.类的加载机制分为五个部分:加载,验证,准备,解析,初始化类加载器有三种…...

    2024/4/26 12:06:09
  10. QTTabBar 「资源管理器」让你的文件夹拥有浏览器标签页般的体验

    前言 对于广大使用 Windows 系统的同学们来说,「资源管理器」一定是大家再熟悉不过的一位老伙计了,说起名字可能还会有不知道的同学,但我要是说起「文件夹」,大家的脑海里应该立刻就能浮现出熟悉的画面:一个四四方方的小盒子里,放着我们所有的文件:音乐、视频、软件………...

    2024/4/15 4:26:06
  11. 用python的turtle库画个笑脸(附代码)

    前言 其实在学校没学过Python,只不过这次疫情在家着实有点闲,所以就借机看了看Python。就感觉python太强了,而且在实现相同效果下更简单。学过C,C++和C#,python我感觉算是最简单的了(可能是因为我接触的少吧)。看了mooc上的一些视频,就开始展示展示吧。 第一次学的库就…...

    2024/4/24 12:42:45
  12. Cute FTP,除了Cute FTP以外,关于好用ftp工具推荐以及使用教程

    FTP是一种文件传输下载方式,它是TCP/IP协议栈的一部分;其中FTP又由两部分组成,一部分是FTP的服务器,另一部分是FTP的客户端!它能够高效安全地进行文件传输下载操作!可以使用服务器管理工具来作为FTP的客户端,进行FTP的操作,实现FTP的下载安装等! IIS7服务管理器,它最…...

    2024/4/28 3:48:54
  13. AI解救“工具人”:RPA+AI,让万物皆可自动化

    首先:UiBot Mage是什么 脱离机械劳动、走向创造性工作,这听起来就很有未来感。 那UiBot Mage究竟是如何调用AI来自动化完成工作的呢? 这要从RPA开始讲。 RPA,Robotic Process Automation的简称,也就是机器人流程自动化。 这类服务可以让一些存在于电脑屏幕UI界面上繁琐固定…...

    2024/4/24 12:42:45
  14. 非常强悍的 RabbitMQ 总结,细节写得真好

    rabbitMQ是基于AMQP协议的,通过使用通用协议就可以做到在不同语言之间传递。AMQP协议核心概念server:又称broker,接受客户端连接,实现AMQP实体服务。connection:连接和具体broker网络连接。channel:网络信道,几乎所有操作都在channel中进行,channel是消息读写的通道。客…...

    2024/5/3 14:02:09
  15. 《FPS关卡设计》笔记(二)

    第五章:战场设计战场必须必须包括没有掩体的危险区域。既要有危险区域,也要有安全区域,为玩家提供明确的选择。玩家可以选择守候在安全区域,等待敌人上门,也可以冒着危险绕到敌人身后,从背后突袭。好的战场一般需要具备下面几个条件:至少有3~4挑岔路有不含掩体的危险区域…...

    2024/5/3 20:49:28
  16. LG解bl锁并获取root

    LG解bl锁(无需临时root、降级)并获取root 昨天刷回官方之后怎么也不爽,寻思着整个root。 漠云大佬提供的教程https://bbs.lge.fun/thread-155.htm?onlyhost=1 (某鱼上部分人帮解锁root的就是用的这个) 但里面需要获取临时root,并降级。上gresslg大佬搬运的kdz仓库上去看…...

    2024/4/24 12:42:40
  17. java类加载顺序

    无继承时的类加载顺序 静态变量、静态代码块(顺序由书写顺序决定) 变量、匿名代码块 构造方法 调用时执行静态方法有继承时的类加载顺序 父类静态变量、静态代码块(顺序由书写顺序决定) 子类静态变量、静态代码块(顺序由书写顺序决定) 父类变量、匿名代码块 父类构造方法…...

    2024/4/24 12:42:40
  18. 凌姗说币:6.11BCH,LTC,EOS行情分析及操作建议

    凌姗赠言:交易,不要在乎一张单,一个点的得失,但一定要重视市场最终运行的方向,因为,在顺风里,你只需张开风帆,就能轻松抵达止盈的彼岸! 【消息资讯】 1.中证协2020百项重点研究课题敲定,涉及区块链的课题项目多达6项。2.贵阳将分两期建成主权区块链基础设施示范工程项…...

    2024/5/6 6:53:35
  19. HashMap的实现原理是什么?

    HashMap是根据Map接口实现的一种键值对数据结构,其中允许出现null的键或值;其顺序不固定。在Java中,基本类型可看做基础数据类型和引用类型(用于模拟C/C++中的指针),HashMap实际上是一种数组+链表的结合体。在JDK1.8之后,一旦链表的节点数据超过八个,就会将底层转为红黑…...

    2024/5/3 16:11:00
  20. 跨域出现Provisional headers are shown 报错

    原因一 服务器禁止跨域(优先查找),让后端设置允许跨域 原因二 检查自己电脑网络...

    2024/4/24 12:42:37

最新文章

  1. 5.合并两个有序数组

    文章目录 题目简介题目解答解法一 &#xff1a;合并后排序解法二&#xff1a;双指针排序 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 合并两个有序数组 相关的讲解&#xff01;&#x1f600; 题目简介 题目解答 解法一 &#xff1a;合并后排序 假设我们要合…...

    2024/5/8 5:59:23
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/7 10:36:02
  3. 磁盘管理与文件管理

    文章目录 一、磁盘结构二、MBR与磁盘分区分区的优势与缺点分区的方式文件系统分区工具挂载与解挂载 一、磁盘结构 1.硬盘结构 硬盘分类&#xff1a; 1.机械硬盘&#xff1a;靠磁头转动找数据 慢 便宜 2.固态硬盘&#xff1a;靠芯片去找数据 快 贵 硬盘的数据结构&#xff1a;…...

    2024/5/8 2:36:28
  4. 《c++》多态案例一.电脑组装

    一.代码展示 #include <iostream> using namespace std; class CPU { public://抽象计算函数virtual void calculate() 0;};class CVideoCard { public://抽象显示函数virtual void display() 0;}; class Memory { public://抽象存储函数virtual void storage() 0;};…...

    2024/5/5 8:48:19
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/7 5:50:09
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/7 9:45:25
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/7 14:25:14
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/7 11:36:39
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/4 23:55:17
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/7 9:26:26
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/4 23:55:06
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/4 23:55:16
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/6 21:42:42
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/4 23:54:56
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57