精华内容
下载资源
问答
  • 中考语文满分作文划过美丽弧线的倒钩
  • 模拟用户弧线滑动,算法python实现

    千次阅读 2017-11-07 18:10:34
    下面就介绍一种计算两个点直线弧线路径的方法,并通过 python 和 sikuli 实现弧线滑动弧线坐标计算已知 A、B两点坐标分别为(x1,y1)、(x2,y2),求经过A、B两点的弧线,显然这样的弧线有无数条,需要再加上限定条件...

    前言

    用自动化软件执行脚本时,其中拖拽、滑动等这些操作往往是直线,而实际用户滑动时一般都不是直线,可能是一段弧线或者更复杂的线。

    下面就介绍一种计算两个点直线弧线路径的方法,并通过 python 和 sikuli 实现弧线滑动

    弧线坐标计算

    已知 A、B两点坐标分别为(x1,y1)、(x2,y2),求经过A、B两点的弧线,显然这样的弧线有无数条,需要再加上限定条件,弧线的弧度φ,也就是A、B两点和圆心连线的夹角,范围是(0, π),限定弧度后,这样的弧线就只剩两条了。

    1. 求出圆心坐标

    如图,先考虑B在A右上方,弧线位于AB下方的情况:
    这里写图片描述
    一开始想用圆心坐标列二元二次方程组,比较麻烦,就改用三角函数来运算,效果很好。主要思路就是求出其中一条半径 OA的长度和斜率,再通过 A 点坐标增量的方式求出圆心 O 的坐标

    AB的长度 d = ((x2-x1)^2 + (y2-y1)^2) ^(1/2)
    OA与AB的夹角 α= (π - φ)/2
    根据正弦定理求半径 r = d/sinα* sinφ
    AB与x轴的夹角 β= arctan((y2-y1)/(x2-x1))
    OA与x轴的夹角 γ=α+β
    最后O点坐标为 (x0, y0) = (x1+r*cosinγ, y1+r*sinγ)

    其他情况处理:
    图中各条线的相对位置只是一种情况,其他情况计算公式可能稍有不同,某些地方的加减号可能要互换。经过验证,只要把求β的步骤中的arctan(a)换成一个二元函数atan2(x,y)就可以适应各种情况了。
    具体就是 β= atan2((y2-y1),(x2-x1))
    atan2和arctan的不同之处是,arctan返回的是一个180°的范围(-π/2, π/2)的值,而atan2(x, y)则会根据x, y值是正数还是负数,也可以理解成点(x, y)所在的象限,返回一个360°范围(-π, π)的角度值,并且这个角度的正切值是 y/x 。
    具体验证过程就不写了,atan2函数在python的math包里有,后面代码部分会介绍。

    2. 求出弧线上采样点的坐标

    知道了圆心(x0,y0)和半径r,可以求出圆上任意一点的坐标。但是我们要的是画出A点到B点之间的一段弧线。而让软件画出这段弧线,其实就是要在某种索引下,将鼠标或者模拟手指(触屏设备),依次划过这段弧线上离散采样的n个点。

    那这个索引选什么比较好呢,首先想到坐标x,y中的一个作为索引,但这样是不行的,因为单一一个横坐标或者纵坐标与点不是一一对应的,给出一个x,求圆上的点有可能求出两个y

    索引可以选择点所在的半径和x轴的夹角,夹角与圆上的点一一对应的,用atan2(x,y)函数也能很容易的求出夹角来。

    首先要有已知圆上点坐标求夹角的公式,这样才能分别求出起始和结束点的夹角,已确定夹角作为索引时的其实和结束范围

    圆上点(x,y)的夹角α = atan2(x-x0, y-y0)
    那么起始点A的夹角 α1 = atan2(x1-x0, y1-y0)
    结束点B的夹角 α2 = atan2(x2-x0, y2-y0)

    已知夹角求圆上点的坐标,因为sin和cos都是周期为2π的,所以这里夹角的取值范围不需要限制在(-π,π )之间,可以是任意值:

    x = x0 + r*cosα
    y = y0 + r*sinα

    确定索引范围
    知道起始和结束的夹角,如果需要采样n个点,把起始和结束点之间分割成n个角度,再求出对应点的坐标,不就可以了吗?有时可能没那么简单,之前还需要加一步,夹角范围翻转,如图:
    这里写图片描述

    当AB之间夹角跨度超过180°时,虽然我们想要的是实线部分较短的这一段弧线,但直接用α1和α2的话,得到的会是虚线部分,较长的这一段弧线。因此要首先进行判断,如果α1减α2的绝对值大于π,则需要将其中较小的一个加上2π,这样才能得到较短的那段弧线

    代码实现

    这里使用python和sikuliX,sikuliX(http://www.sikulix.com/)是一款基于计算机视觉的自动化工具。

    from __future__ import division
    import random
    import math
    
    def distance(location1, location2):
        return math.sqrt((location1.getX() - location2.getX())**2 + (location1.getY() - location2.getY())**2)
    
    def getCircleXY(a, x0, y0, r):
        x = x0 + r * math.cos(a)
        y = y0 + r * math.sin(a)
        return (x,y)
    
    def getAngleXY(x, y, x0, y0):
        return math.atan2(y-y0, x-x0)
    
    def getAngle(location1, location0):
        return getAngleXY(location1.getX(), location1.getY(), location0.getX(), location0.getY())
    
    def dragDropX(location1, location2, dragTime):
        print "[Debug]start dragDropX function"
        x1 = location1.getX()
        y1 = location1.getY()
        x2 = location2.getX()
        y2 = location2.getY()
        connerA = math.pi / 6
        connerB = (math.pi - connerA)/2
        d0 = math.sqrt((x2-x1)**2 + (y2-y1)**2)
        r = d0 * math.sin(connerB)/math.sin(connerA)
        connerC = math.atan2((y2-y1),(x2-x1))
        connerD = connerC + connerB
    
        x0 = x1 + r * math.cos(connerD)
        y0 = y1 + r * math.sin(connerD)
        location0 = Location(x0, y0)
    
        startPoint = location1
        endPoint = location2
        startAngle = getAngle(startPoint, location0)
        endAngle = getAngle(endPoint, location0)
        if abs(endAngle - startAngle) > math.pi:
            if endAngle < startAngle:
                endAngle += math.pi * 2
            else:
                startAngle += math.pi * 2
    
        n = 30
        jitter = math.ceil(r * abs(endAngle - startAngle)/n/10)
        mmd = Settings.MoveMouseDelay
        threadLock.acquire()
        mouseMove(startPoint)
        mouseDown(Button.LEFT)
        Settings.MoveMouseDelay = dragTime/n  
        angleStep = (endAngle - startAngle) / n
        for i in range(n):
            angle = startAngle + angleStep * i
            lo = getCircleXY(angle, x0, y0, r)
            mouseMove(Location(lo[0]+random.randint(-jitter,jitter), lo[1]+random.randint(-jitter,jitter)))
        mouseMove(endPoint)
        mouseUp(Button.LEFT)
        threadLock.release()
        Settings.MoveMouseDelay = mmd

    实现效果

    利用sikuliX编辑脚本,在屏幕上查找两个形状,再从一个执行弧形滑动到另一个形状。
    这里写图片描述

    下面为效果图,不同颜色对应不同的弧度值,分别是60°、30°、15°、7.5°
    这里写图片描述

    展开全文
  • 1、效果图 2、HTML: <div class="testA"></div> 3、CSS .testA{ width: 100px; height: 50px; background-color: #F0F2FA; margin-left: 50px; position: relative;... border-t

    1、效果图

    在这里插入图片描述

    2、HTML:

    <div class="testA"></div>
    

    3、CSS

    .testA{
            width: 100px;
            height: 50px;
            background-color: #F0F2FA;
            margin-left: 50px;
            position: relative;
            border-top-left-radius: 10px;
            border-top-right-radius: 10px;
            &::before{
                content: '';
                // width: 0px;
                // height: 0px;
                position: absolute;
                left: -10px;
                bottom: 0;
                transform: rotate(-90deg);
                width: 10px;
                height: 10px;
                background-image: radial-gradient(circle at 12px -2px, #fff 12px, #F0F2FA 12px)
            }
            &::after{
                content: '';
                position: absolute;
                right: -10px;
                bottom: 0px;
                transform: rotate(0deg);
                width: 10px;
                height: 10px;
                background-image: radial-gradient(circle at 12px -2px, #fff 12px, #F0F2FA 12px)
            }
        }
    
    展开全文
  • 双子座流星雨

    2011-12-11 01:22:00
    和史蒂芬说,“如果你从没见过双子座流星群流星在广阔的夜空中划过一道道明显的 弧线 ,那么你就不能说你见过流星。”    那么,什么时候观看双子座流星群最合适?这取决于你所在的位置。当夜幕刚刚降临,双子...

    双子座阿尔法流星雨

      活动期:每年在12月7日至17日前后出现

     

      极盛日期:12月13日——14日达到高潮;(传统极大为15日0:40)

     

      最大每小时流星数(ZHR):120

     

      辐射点位置:赤经:7 h 28m( 125度 ),赤纬+31度

     

      靠近辐射点的亮星:双子座阿尔法星

     

    双子座流星雨

    流行雨特点描述:流星速度中速,流星路径短, 亮流星多, 流星多为白色.同时不乏红,黄,蓝,绿等多种颜色,是一年中最绚烂,最稳定的流星雨。

     

      彗星母体:Phaethon彗星。周期为1.4年,轨道很扁,最近离太阳0.15天文单位。

     

    发现历史

      很多熟悉的流星群非常古老,如英仙和狮子。但双子流星群却很年轻,19世纪中叶才出现,而且一开始时流量较低,每小时有10-20颗。从那以后,每年它的流量都在增加,目前已成为每年主要的流星群了。1998年人们观测的双子流星群达到每小时ZHR=140颗。在极大时,观测条件不错的观测者可以看到比较多的流星。[1]

     

    形成原因

      很多熟悉的流星群非常古老,如英仙和狮子。但双子流星群却很年轻,19世纪中叶才出现,而且一开始

     

    12月13日晚流星雨

    时流量较低,每小时青岛市民抓拍双子座流星雨有10-20颗。从那以后,每年它的流量都在增加,目前已成为每年主要的流星群了。1998年人们观测的双子流星群达到每小时ZHR=140颗。在极大时,观测条件不错的观测者可以看到比较多的流星

     

      自从1862年人们注意到双子座流星群后,就一直在寻找它的母彗星。直到1983年,卫星才发现了与它有相同轨道的不是一颗彗星,而是一个石质的小行星。编号 3200 Phaethon。这个小行星的周期为1.4年,轨道很扁,最近离太阳0.15天文单位。1997年12月它经过地球附近时距离我们只有0.31天文单位。

     

      人们一直在争论Phaethon到底是一个小行星还是一个彗星。它的光谱看上去象石质小行星,但轨道却很象彗星。它经过太阳旁时没有出现彗尾,但却有碎块产生,形成了流星雨。通过分析双子火流星的照片,科学家们估计出双子流星物质的密度为1-2m/cc,比标准的小行星的3 gm/cc的密度要低,但却比彗星0.3 gm/cc的密度大几倍。有人认为Phaethon是一个耗尽的或休眠的彗星,外表面积聚了厚的行星际尘埃。因此它会有小行星的外表,却有彗星的内核。

     

      2009年双子座流星雨将从12月7日一直持续到17日。2009年双子座流星雨将于12月14日夜晚到12月15日凌晨之间达到极盛。

     

    观测时间

      对于那些乐意冒着严寒观看流星群的人来说,双子座流星群是一个在冬天里相当有特

     

    青岛市民抓拍双子座流星雨

    色的景观,甚至超过八月的英仙座流星12月13日晚流星雨群。天文学家戴维和史蒂芬说,“如果你从没见过双子座流星群流星在广阔的夜空中划过一道道明显的弧线,那么你就不能说你见过流星。”

     

      那么,什么时候观看双子座流星群最合适?这取决于你所在的位置。当夜幕刚刚降临,双子座α星就开始出现在东部或东北地平线,这时你最好待在户外,直到月亮升起来。

     

      在此期间,你还有可能看到与众不同的Earth-grazing流星,流星从地平线出现(有时甚至低于地平线),拖得长长的尾巴接近水平地滑过大气层。因此,最佳的观看时间是前半夜至午夜、夜幕降临至月亮升起这段时间。

     

      冬天观看流星群可是一个漫长而寒冷的事,必须耐心等候流星群的出现。如果

     

    双子座流星雨

    它们还未出现,就感到冷得不行,那你就有可能坚持不了多久。因此,确保能在一个温暖舒适的环境下观察流星群。

     

      双子座流星雨是一个很守信用的流星雨,每年都要定期出现。双子座从傍晚升起来,直到天亮前还高挂天空,整夜都可看到。

     

      天文专家说,双子座流星雨区别于狮子座流星雨的一个显著特点是流星的星体亮度大、速度中等、色彩丰富,对于目视观测者来说具有很强的吸引力, 而且其流星的数量比上月的狮子座流星雨还要大。在理想的天空条件下,每小时的理论天顶流星数在120颗左右。[2]

    转载于:https://www.cnblogs.com/yifenghong/archive/2011/12/11/2283698.html

    展开全文
  • 本文是对一些app第一个页面的“跳”按钮及一些缓冲框的实现。一个控件就详细写一篇文,未免过于麻烦,所以这里是做了一个汇总,只写核心思路及相关伪代码,几个控件写成一篇。后面会给出完整代码。1. 矩形倒计时...

    前言

      最近自定义控件的实践相对多一些,看到了别人app上实现的效果就想自己动手尝试下,看自己能不能做到。本文是对一些app第一个页面的“跳过”按钮及一些缓冲框的实现。一个控件就详细写一篇文,未免过于麻烦,所以这里是做了一个汇总,只写核心思路及相关伪代码,几个控件写成一篇。后面会给出完整代码。

    1. 矩形倒计时“跳过”

      1. 先来看一下最终效果:

    image

      2. 基本思路及相关代码

      首先,我们看到“跳过”这两个字的背景是一个圆角矩形,而控件的形状一般是矩形,这时,我们把控件的背景设置成透明的,然后在控件上画出圆角矩形就可以了。

    private int mBgColor = Color.TRANSPARENT;
    // 画出控件背景色,为透明
    canvas.drawColor(mBgColor)
    
    //圆角矩形内填充的颜色,默认是半透明的黑色
    private int mRectFillColor = 0x32000000;
    //控件坐标系移至控件中心位置
    canvas.translate(mWidth / 2, mHeight / 2);
    //在其上画出圆角矩形,圆角大小由外界决定
    mPaint.setColor(mRectFillColor);
    RectF rectF = new RectF(-mWidth / 2, -mHeight / 2, mWidth / 2, mHeight / 2);
    canvas.drawRoundRect(rectF, mCornerX, mCornerY, mPaint);

      控件坐标系原点之所以移到控件的中心,是因为我们所画的内容基本上都是基于控件中心坐标的,移过去之后,我们更好确定我们所画内容的坐标。mBgColor、mRectFillColor、mCornerX、mCornerY都可以通过设定其set方法由控件外决定其值。

      其次,“跳过”这两个字以及倒计时的数字,我们希望它们能够被视为一个整体,置于控件的中心。那我们要做的就是先计算出这两字以及倒计时数字的宽度。另外,注意,一般“跳过”俩字跟倒计时数字是有间距的。

    private int mTextSize = 14;
    //估算出字体的宽度
    mPaint.setTextSize(getResources().getDisplayMetrics().scaledDensity * mTextSize);
    mPaint.setTextAlign(Paint.Align.LEFT);
    
    Rect rect = new Rect();
    mPaint.getTextBounds(text, 0, text.length(), rect);
    float textWidth = rect.right - rect.left;
    
    private int mNumberTextSize = 12;
    //估算出数字的宽度
    mPaint.setTextSize(getResources().getDisplayMetrics().scaledDensity * mNumberTextSize);
    mPaint.setTextAlign(Paint.Align.LEFT);
    
    Rect rect1 = new Rect();
    mPaint.getTextBounds("3", 0, 1, rect1);
    float numberWidth = rect1.right - rect1.left;

      计算“跳过”两个字宽度、计算倒计时数字宽度的方法是一样的,都是给画笔设置了textSize,然后用画笔的getTextBounds方法计算。算出了“跳过”两字和倒计时数字的宽度,如果两者有间距的话就能计算出这两者看做一个整体时,这个整体的宽度

    //字体与数字之间的间距
    private float mDivider = 15;
    //总长度,中间添加间距
    float length = textWidth + mDivider + numberWidth;

      有了这个宽度就可以计算出,“跳出”和倒计时数字的基线坐标了:

    mPaint.setTextAlign(Paint.Align.LEFT);
    Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
    “跳过”两字的基线坐标(jumpLoc):(-length / 2,(-fontMetrics.top - fontMetrics.bottom) / 2)
    
    mPaint.setTextAlign(Paint.Align.LEFT);
    Paint.FontMetrics fontMetrics1 = mPaint.getFontMetrics();
    倒计时数字的基线坐标(numberLoc):(-length / 2 + textWidth + mDivider,(-fontMetrics1.top - fontMetrics1.bottom) / 2)

      最后,算出了基线坐标就可以分别画出“跳出”和倒计时数字了:

    mPaint.setColor(mTextColor);
    mPaint.setTextSize(getResources().getDisplayMetrics().scaledDensity * mTextSize);
    canvas.drawText(text, jumpLoc.x, jumpLoc.y, mPaint);
    
    mPaint.setColor(mNumberTextColor);
    mPaint.setTextSize(getResources().getDisplayMetrics().scaledDensity * mNumberTextSize);
    canvas.drawText(mDelayTime + "", numberLoc.x, numberLoc.y, mPaint);

      还有一点,标识倒计时数字的变量mDelayTime,本例是通过Timer完成倒计时。每过1秒,就向主线程发送一个消息,由主线程去控制mDelayTime的变化并重画控件(invalidate)。这部分代码看源码吧,在ThreeSecondJump0类中。

    2. 圆形倒计时“跳过”

      1. 最终效果如下:

    image

      2. 基本思路及相关代码

      如上效果,是看了网易新闻的splash页做的。首先,还是需要平移控件坐标系,画透明背景,把画笔设置成填充模式画一个圆,这些跟上面控件类似,在这里就不重复说了。这里说下面几个点:画“跳过”两字、画动态变化的红色边界。

      画“跳过”两字

      仔细看“跳过”两个字,会发现它的大小基本上是跟圆边界顶着的,我们需要设置合适的大小才能够做到这样的效果,那怎么才能获取合适的大小呢?本例是通过循环得到的

    do {
        mPaint.setTextSize(mTextSize);
        Rect rect = new Rect();
        mPaint.getTextBounds("跳过", 0, 2, rect);
        textWidth = rect.right - rect.left;
        textHeight = rect.bottom - rect.top;
    
        if (Math.pow(textWidth / 2, 2) + Math.pow(textHeight / 2, 2) > Math.pow(mCircleRadius, 2)) {
            mTextSize -= 0.5;
        } else {
            break;
        }
    
    } while (true);

      使textSize逐渐缩小,直至字体的宽一半的平方与字体高一半的平方之和不再大于圆半径的平方。仔细思考下,前后两者的值正好相等时,包含字体的矩形正好“顶着”外部的黑色圆边界。从循环中跳出之后就正好是顶着圆边界的textSize了,然后估算出基线坐标,画出“跳出”两个字就可以了

    //字体的颜色
    private int mTextColor = Color.WHITE;
    
    mPaint.setColor(mTextColor);
    Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
    canvas.drawText("跳过", -textWidth / 2, (-fontMetrics.top - fontMetrics.bottom) / 2, mPaint);
      画动态变化的红色边界

      首先,画边界很简单,只需把画笔模式设置为stroke,半径与上述黑色圆半径一样,再设置上颜色和strokeWidth,基本就可以画出这个红色边界了

    private int mCircleStrokeColor = Color.RED;
    
    mPaint.setColor(mCircleStrokeColor);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeWidth(mStrokeWidth);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    
    Path path = new Path();
    path.addCircle(0, 0, mCircleRadius, Path.Direction.CW);
    canvas.drawPath(path, mPaint);

      但上述代码只是能画出一个静态的红色边界,自己不会动的。我们还需要使用属性动画及PathMeasure使之动起来

    ...//省略上述Paint设置部分
    
    Path path = new Path();
    path.addCircle(0, 0, mCircleRadius, Path.Direction.CW);
    
    //将此path交给一个PathMeasure对象
    PathMeasure pathMeasure = new PathMeasure(path, false);
    float length = pathMeasure.getLength();
    Path pathDst = new Path();
    //mCurrentValue,即为动画某一时刻的值
    //getSegment可以获取此path的片段
    pathMeasure.getSegment(mCurrentValue * length, length, pathDst, true);
    canvas.drawPath(pathDst, mPaint);

      上述就可以画出一个动态的红色边界了,但此边界的起点是在x轴的正半轴上的,我们希望边界起点在y轴的负半轴。也好解决,暂时将控件坐标系逆时针旋转90度,然后再画path,画完path之后再恢复控件坐标系即可

    canvas.save();
    
    canvas.rotate(-90);
    
    ...//省略的内容为上述画path部分
    
    canvas.restore();

      到此,起点在y轴负半轴、动态变化的红色边界就画完了。

    3. 仿ios菊花缓冲图标

      最终效果图如下:

    image

      基本思路及相关代码

      模仿ios的缓冲图标来写的,但不知道ios那边具体是如何实现的。我的实现效果总感觉不那么好,不知道是不是因为图片的问题。下面是我的基本思路:

      简单来讲,就是找了一张图片,然后给这张图片一个动画让它不停地旋转。那怎么使图片不停地旋转呢?本示例使用的Matrix的postRotate。下面一步一步来讲,一开始还是给控件画透明背景,将控件坐标系原点移到控件中心,这里不再多说。接下来就是画图片了,画图片有几个重载的方法,因为我们要用到矩阵的旋转,所以最终选择了如下这个方法:

    public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint)

      第一步,先从应用资源中获取所要旋转的图片

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.loading);

      调用drawBitmap时,默认图片的左上角是跟坐标系原点重合的,而我们是想让图片居中显示,这就需要第二步,平移图片将图片中心与坐标系原点重合为一点。我们且看drawBitmap的第二个参数Matrix,此矩阵会作用于bitmap的坐标,使bitmap完成平移、旋转、缩放或者错切的操作。我们现在需要平移,需调用matrix的translate相关方法进行操作:

    Matrix matrix = new Matrix();
    //向x轴负半轴和y轴负半轴平移宽度的一半、高度的一半
    matrix.postTranslate(-bitmapW / 2, -bitmapH / 2);

      平移过后就可将图片的中心与坐标系的中心置于同一点了。平移之后,还会有一个问题:控件的宽高是由控件外设置的,而图片的大小是固定的,这就可能造成图片太大在控件内显示不全或图片太小不能够很好地显示在控件中。这就需要第三步,缩放图片。缩放到图片的较大边刚好跟控件的较小边重合,当然为了更好一些的显示效果,我们可以让这两个边留一些间距

    //图片的宽高是一样的,所以只获取一个宽就可以了
    int bitmapWH = bitmap.getWidth();
    //找出控件宽高较小的
    int temp = mWidth > mHeight ? mHeight : mWidth;
    int tempContent = temp - mPadding;
    
    //控件的较小边比图片的宽或高大多少倍
    float s = tempContent * 1.0f / bitmapWH;
    
    Matrix matrix = new Matrix();
    //这是上一步说明过的平移
    matrix.postTranslate(-bitmapWH / 2, -bitmapWH / 2);
    matrix.postScale(s, s);
    canvas.drawBitmap(bitmap, matrix, mPaint);

      计算出当前控件的较小边是当前图片宽度或高度的多少倍,然后调用postScale等比例缩放,至此缩放完毕。以上的三步也只是画出了一个静态的图片并将其缩放到合适的宽高,而我们需要的是图片旋转起来。使图片旋转使用的就是matrix.postRotate这个方法,动起来就需要使用属性动画来不断改变图片旋转的角度来实现了:

    //画图片
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.loading);
    //图片的宽高是一样的,所以只获取一个宽就可以了
    int bitmapWH = bitmap.getWidth();
    //找出控件宽高较小的
    int temp = mWidth > mHeight ? mHeight : mWidth;
    int tempContent = temp - mPadding;
    
    //控件的较小边比图片的宽或高大多少倍
    float s = tempContent * 1.0f / bitmapWH;
    
    Matrix matrix = new Matrix();
    matrix.postTranslate(-bitmapWH / 2, -bitmapWH / 2);
    matrix.postScale(s, s);
    //此处的mCurrentValue为属性动画0-1变化时某一个时刻的值
    matrix.postRotate(360 * mCurrentValue);
    canvas.drawBitmap(bitmap, matrix, mPaint);

      至此,旋转缓冲控件完成。

    4. 仿交通银行缓冲框

      手里有一张交通的卡,然后就下载了交通银行的app用,觉得他们的缓冲框挺有意思的,然后就想实现以下。

      最终效果图如下

    image

      基本思路及相关代码

      基本思路大致是这样的:先使用Path画两个圆弧,使用某种方式让这两个圆弧的某一个点连接,然后为此Path创建一个PathMeasure对象,调用其getSegment方法获取此path的某一个片段,最后使用属性动画使此片段动起来。

      首先,使用path画两个几乎为圆的圆弧,并保证第一个圆弧的最后一个点可以跟第二个圆弧的第一个点连接。而在画出第一个圆弧之前我们需要得到这些圆弧的半径

    //计算出单个圆的半径
    //当所画内容的宽尽量填充控件的宽时单个圆的半径
    float radius0 = (mWidth - mPadding) * 1.0f / 4 - mStrokeWidth;
    //当所画内容的高尽量填充控件的高时单个圆的半径
    float radius1 = (mHeight - mPadding) * 1.0f / 2 - mStrokeWidth;
    //较小值即为合适的半径
    float radius = radius0 > radius1 ? radius1 : radius0;

      说明下,mPadding为所画的内容控件边界的间距,mStrokeWidth为圆弧边界的宽度。上述代码的意思是,先计算出所画内容的宽高尽量填充控件宽高时的半径,为了使所画内容始终保持在控件内,选择这两个半径中的较小半径。接下来就是,画两个圆弧了:

    //透明背景
    canvas.drawColor(mBgColor);
    
    //控件坐标系平移到控件中心
    canvas.translate(mWidth / 2, mHeight / 2);
    
    //画出背景轨道
    mPaint.setColor(mCirCleBgColor);
    mPaint.setStrokeWidth(mStrokeWidth);
    
    Path path = new Path();
    
    RectF rectF = new RectF(0, -radius, 2 * radius, radius);
    //这里虽然可以设置成-360,但设置成-360就会有问题,多了一条线
    path.addArc(rectF, 180, -359.99f);
    
    
    RectF rectF1 = new RectF(-2 * radius, -radius, 0, radius);
    path.arcTo(rectF1, 0, 359.99f);
    
    canvas.drawPath(path, mPaint);

      前两句代码是画出控件的透明背景、将控件坐标系的原点移至控件的中心。之后设置画笔的颜色及stroke宽度,接着是画两个圆弧,第一个圆弧是从180度开始画起,逆时针359.99度,结合包含此圆弧的矩形坐标可知,这个圆弧的起始点是坐标系原点,最后一个点是一个十分接近坐标系原点的点,而画第二个圆弧使用的是path.arcTo,这就能保证第二个圆弧的起始点与第一个圆弧的最后一个点连接(arcTo方法的特性)。第二个圆弧的起始点是坐标系原点,最后一个点是十分接近坐标系原点的点,并没有连接在一起。

      这里有一个插曲,如果添加第一个圆弧到path时设置的不是-359.99f,而是-360f(划过的角度是可以设置成-360f的),就会莫名其妙是多一条直线。此直线并不是第二个圆弧的最后一个点与第一个圆弧起始点的连线(之所以这么想,是因为以为path自动闭合了),所以,就比较诡异,只能设置成一个十分靠近-360的值了。

      其次,要做的是根据此path创建一个PathMeasure对象

    //画动态的变化
    //设置画笔的颜色
    mPaint.setColor(mCircleColor);
    
    //根据上述path创建PathMeasure
    PathMeasure pathMeasure = new PathMeasure(path, false);
    //pathMeasure可以计算出上述path的总长度
    float length = pathMeasure.getLength();
    //mCurrentValue为在0~1之间变化的属性动画某一刻的值
    //startD,是获取的path片段的起始点,
    //随着mCurrentValue的变化,startD从path的起始点变化到最后一点
    float startD = mCurrentValue * length;
    Path pathDst = new Path();
    //ratio为动态线的长度
    if (mCurrentValue + ratio <= 1) {
        float stopD = (mCurrentValue + ratio) * length;
        pathMeasure.getSegment(startD, stopD, pathDst, true);
    } else {
        //先取出startD-length这个片段
        pathMeasure.getSegment(startD, length, pathDst, true);
        Path pathDst0 = new Path();
        //再从头取出不足mCurrentValue + ratio的片段
        pathMeasure.getSegment(0, (mCurrentValue + ratio - 1) * length, pathDst0, true);
        //都结合到path中
        pathDst.addPath(pathDst0);
    }
    
    canvas.drawPath(pathDst, mPaint);

      通过getSegment获取path的片段,片段的起始点距离path起始点的距离startD为:mCurrentValue * length,大部分情况下,片段的最后一点距离path起始点的距离stopD为:(mCurrentValue + ratio) * length,这样写可使动态变化弧线的长度固定为ratio * length。而少部分情况下,mCurrentValue + ratio已经大于1,这时候就需要先取出start~length这个片段,然后再从path的起始点取出另一个片段,使两个片段的长度之后为ratio * length。

      至此,仿交通银行的缓冲框已经制作完毕。

    总结

      两个“跳过”、两个缓冲框,实现起来大多都会用到属性动画完成动态效果,定时器本身也可以被动画替代。比较有挑战的,大概就是旋转图片时会用到矩阵的操作,完成一些动态效果时会用到PathMeasure来完成。其它可说的并没有太多,毕竟只是一些简单的效果。

      这里是完整代码

    展开全文
  • 关注+星标公众号,不错过精彩内容来源 |网络公众号|嵌入式专栏硬件工程师划过无数的走线,那么,你掌握几种?01AD布蛇形线方法Tool里选Interactive length tun...
  • Android绘图篇(一)——Canvans基本操作

    千次阅读 2019-03-14 21:27:47
    注意不是结束角度,是弧线的角度,方向是顺时针。 useCenter:是否显示弧边。 paint:画笔。 注:角度的定义参考高中数学象限知识。 好吧,画一个试试呗: //绘制弧线 RectF rect = new ...
  • Android中drawArc弧度参数详解

    千次阅读 2019-03-07 08:50:44
    在drawArc中startAngle 是弧形的起始角度 sweepAngle 是弧形划过的角度 下面我们来详细解说一下这两个属性 以这张图为例startAngle的角度是从x轴的右侧开始为0度 也就是说 当我们给定startAngle角度为90度时,...
  • 这个相对简单,主要是确定开始角度,并不断增加绘制划过角度,圆弧就出现在界面中了,这里需要注意的是RectF oval的大小确定: 在确定RectF oval之前,我们要先测量确定当前控件的宽高,根据当前控件的宽高来确定...
  • 圆弧划过的角度为: 2 * angle 这一块的代码如下: // mProgressWidth为进度条的宽度,根据当前进度算出进度条的位置 mCurrentProgressPosition = mProgressWidth * mProgress / TOTAL_PROGRESS; // 即当前位置...
  • android安卓源码海量项目合集打包-1

    万次阅读 多人点赞 2019-06-11 16:16:24
    下载地址 最后更新共计113个分类5177套源码29.2 GB。 卷 新加卷 的文件夹 PATH 列表 卷序列号为 00000200 5E7A:7F30 F:. ├─前台界面 │ ├─3D标签云卡片热门 │ │ Android TagCloudView云标签的灵活运用.rar ...
  • 首先,计算偏移坐标,即用户手指划过的像素点。然后根据控件的上限值和下限值将它乘以一个相对系数。 根据用户拖动的位置调整上限值或下限值。 设置 CATransaction 的 disabledActions 属性。这会使每个 layer ...
  • series下面的这个areaStyle series: [ { data: count, type: "line", smooth: true, areaStyle: { normal: { color...
  • 什么,你没听说PathMeasure?那你就要OUT咯~ 项目效果图 PathMeasure介绍 更多参考资料 项目效果图 废话不多说,在开始讲解之前,先看下最终实现的效果。 效果一: 仿支付宝支付成功效果 ...
  • 圆弧划过的角度为: [html]   view plain copy 2 * angle  这一块的代码如下: [html]   view plain copy ...
  • 十二

    千次阅读 2014-03-18 22:45:56
    ”说着一屁股坐在地上,使了使劲,随之出一道弧线,粘稠液,吐在了骑车疾驰而的路人身上。那人拖下鞋子,握在手里,够到路压,梆梆梆一通敲击,腾落着鞋子上的泥土,起身穿起鞋子,拍掉了屁股上的脏污,猛的朝下...
  • 花园洋房里的浓烟

    千次阅读 2020-10-17 22:20:01
    第13章 漫花园洋房里的浓烟(1) 刘武生一进院门就傻眼了,偌大个院子像遭了兵燹、水灾、泥石流、地震,变得连他都不认识了。要说呢,墙还是那个墙,房还是那个房,主楼是主楼,客房是客房,可他还是傻眼了,愣愣...
  • 丢掉宝石的孩子

    千次阅读 热门讨论 2010-12-23 20:18:00
    “嗖”地一声,孩子又扔出了一块卵石,不过在扔出这块卵石的时候孩子觉得拿在手里的感觉有些不一样,等他认真看时,发现那块卵石在黄昏下出一道美丽的弧线,果真不一样,原来那是禅师埋下的那颗宝石!可是等到孩子...
  • 运动上肢,使两掌向左右(划弧线)而下,由下成仰掌沿腹胸之前徐徐运劲上托,高不过眉,掌距不大于两肩之距。  (4)旋腕翻掌,掌心朝地,两掌(虎口朝内)运劲下按(沿胸腹之前)成虚掌置于膝盖上部。两肩松开,肘微...
  • 我曾见一场异常悲壮的死亡,正是那次死亡深深的震撼了我,我从此不愿再伤害哪怕再微小的生命……那是在一次围猎班羚的过程中。班羚又名青羊,形似家养山羊,善於跳跃,每头成年班羚重约30多公斤,性情温驯,是...
  • 【转】word 高效经典教程

    千次阅读 2011-10-03 17:03:36
    7、显示宽文档... 16 8、用Word 2000的“透视眼”预视文件信息... 17 F、输入技巧... 17 1、在Word 2000中输入着重号... 17 2、在WORD中输入英语音标... 18 3、给文字标注拼音... 18 4、快速...
  • 我没发火,只是轻轻的拿出钥匙,在它前进的过程中从头到尾的了道优美 弧线 9、 在一地摊上买袜子,一块一双,便宜,本来想买三十双,结果只剩下同一黑色款式的了,卖袜子的忽悠我说,一种颜色好,丢了一只拿其它的顶上...
  • 我没发火,只是轻轻的拿出钥匙,在它前进的过程中从头到尾的了道优美 弧线 9、 在一地摊上买袜子,一块一双,便宜,本来想买三十双,结果只剩下同一黑色款式的了,卖袜子的忽悠我说,一种颜色好,丢了一只拿其它的顶上谁...
  •  哎,事后我们几个还有mm好长时间都食欲不振,没多久大家都消瘦了一番,也许只有mm不太介意:刚好锦上添花,只当让苗条的身材再减减肥吧……   情节10:    有一次冬天的体育课上,学习打军旅拳。  ...
  • 亮丽的绿色,搭配铅笔划过的流畅弧线,给人积极向上的启示; 本PPT模板,适合用于制作企业培训幻灯片,自信心培养、励志等PowerPoint幻灯片; 关键词:绿色PPT背景,铅笔幻灯片背景图片,励志PowerPoint模板下载,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 693
精华内容 277
关键字:

划过的弧线