博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 贝塞尔曲线实践——旋转的七色花朵
阅读量:6226 次
发布时间:2019-06-21

本文共 8932 字,大约阅读时间需要 29 分钟。

hot3.png

一、关于贝塞尔曲线

在工业设计方面贝塞尔曲线有很多用途,同样,在Android中,贝塞尔曲线结合Path类可以实现更复杂的图形,这里我们给一个案例,来实现一种旋转的花朵。对于贝赛尔曲线的理解,建议参考《》,写的非常详细。

 

二、自定义View的误区

今天我们自定义的View效果如下:

对于花朵而言,首先要构建花瓣,花瓣这里使用了三阶贝赛尔曲线,因为二阶贝赛尔曲线画出来的是树叶。

private void buildLeaf(Canvas canvas){        mPaint.setColor(0xff40835e);        int width = getWidth();        int height = getHeight();        if(width==0 || height==0){            return;        }        int centerX = width/2;        int centerY = height/2;        int Radius = Math.max(width,height)/2;        Path path = new Path();        path.moveTo(0,0);       // float leftctrY = - (Radius*4)/5.0f;        float leftctrY = - (Radius*7)/10.0f;        float leftctrX = -(float) (Math.abs(leftctrY) * Math.tan(Math.toRadians(30)));       // path.lineTo(leftctrX,leftctrY);        int lastX = 0;        int lastY = -Radius;        float rightctrY = - (Radius*7)/10.0f;        float rightctrX = (float) (Math.abs(rightctrY) * Math.tan(Math.toRadians(30)));        path.quadTo(leftctrX,leftctrY,lastX,lastY);        path.quadTo(rightctrX,rightctrY,0,0);        path.close();        path.setFillType(Path.FillType.WINDING);        int restoreId = canvas.save();        Paint.Style style = mPaint.getStyle();       // mPaint.setStyle(Paint.Style.STROKE);        canvas.translate(centerX,centerY);        canvas.drawPath(path,mPaint);        mPaint.setStyle(style);        canvas.restoreToCount(restoreId);    }

 

而我们需要的带有弧度的花瓣,因此二阶显然不行,花瓣的画法难度主要集中于三角函数的计算,此外还有第二个控制点的确定,第二个控制点与原点的举例实际上和离原点最远的边平行,此外过最远的点作垂线相交,否则可能产生如下效果。

private void buildHeart(Canvas canvas){        mPaint.setColor(0xffa7324a);        int width = getWidth();        int height = getHeight();        if(width==0 || height==0){            return;        }        int centerX = width/2;        int centerY = height/2;        int Radius = Math.max(width,height)/2;        Path path = new Path();        path.moveTo(0,0);        // float leftctrY = - (Radius*4)/5.0f;        float leftctrY = - (Radius*5)/10.0f;        float leftctrX = -(float) (Math.abs(leftctrY) * Math.tan(Math.toRadians(60)));        // path.lineTo(leftctrX,leftctrY);        int lastX = 0;        float lastY = -Radius * 8f/10;        float rightctrY = - (Radius*5)/10.0f;        float rightctrX = (float) (Math.abs(rightctrY) * Math.tan(Math.toRadians(60)));        path.cubicTo(leftctrX,leftctrY,leftctrX,-Radius,lastX,lastY);        path.cubicTo(rightctrX,-Radius,rightctrX,rightctrY,0,0);        path.close();        path.setFillType(Path.FillType.WINDING);        int restoreId = canvas.save();        Paint.Style style = mPaint.getStyle();        canvas.translate(centerX,centerY);        canvas.drawPath(path,mPaint);        mPaint.setStyle(style);        canvas.restoreToCount(restoreId);    }

 

三、实现自定义View-旋转的花朵

public class FlowerView extends View {    private TextPaint mPaint;    private int strokeWidth = 1;    private int textSize = 12;    private int minContentSize = 0;    private Path mPath;    private int mPetalNumbers = 7;    private float degree;    private int defaultPetalColor = 0xFFFF1493;    private int[] colorSet = new int[]{0xffFF1493,0xffFFD700,0xffFFFF00,0xff87CEFA,0xff00FA9A,0xffBA55D3,0xffE0FFFF};    private boolean isPlaying = false;    public FlowerView(Context context) {        this(context,null);    }    public FlowerView(Context context, @Nullable AttributeSet attrs) {        this(context, attrs,0);    }    public FlowerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        setClickable(true);        initPaint();        minContentSize =  ViewConfiguration.get(context).getScaledTouchSlop() * 2;        mPath = new Path();    }    public boolean isPlaying() {        return isPlaying;    }    private void initPaint() {        // 实例化画笔并打开抗锯齿        mPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG );        mPaint.setAntiAlias(true);        mPaint.setPathEffect(new CornerPathEffect(10)); //设置线条类型        mPaint.setStrokeWidth(dip2px(strokeWidth));        mPaint.setTextSize(dip2px((textSize)));    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int width = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int height = MeasureSpec.getSize(heightMeasureSpec);        if(widthMode!=MeasureSpec.EXACTLY){            width = (int) dip2px(210);        }        if(heightMode!=MeasureSpec.EXACTLY){            height = (int) dip2px(210);        }        setMeasuredDimension(width,height);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        final int width  = getWidth();        final int height = getHeight();        if(width
() { @Override public Float evaluate(float fraction, Float startValue, Float endValue) { return new Float(fraction * 360); } }); animator.setRepeatCount(ValueAnimator.INFINITE); animator.setInterpolator(new LinearInterpolator()); animator.setDuration(3000) .setRepeatMode(ValueAnimator.RESTART); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { setDegree((Float) animation.getAnimatedValue()); } }); } animator.start(); } public void stopRotate(){ isPlaying = false; if(animator!=null){ animator.cancel(); animator = null; } } private void drawFlower(Canvas canvas, int contentSize) { int N = this.mPetalNumbers; for (int i=0;i< N;i++){ drawFlowerPath(canvas,contentSize,N,i); } }//花瓣算法 private void drawFlowerPath(Canvas canvas, int contentSize,int N,int pos) { float perDegree = 360f/N; final float R = contentSize/2f; final float degree = perDegree*pos + this.degree; float endY = (float) (R * Math.sin(Math.toRadians(degree))); float endX = (float) (R * Math.cos(Math.toRadians(degree)));; float firstCtlLength = (float) ((R / 2f) / Math.cos(Math.PI / N)); float leftY = (float) ((firstCtlLength) * Math.sin(degree* Math.PI/180 - Math.PI/N)); float leftX = (float) ((firstCtlLength) * Math.cos(degree* Math.PI/180 - Math.PI/N)); float rightY = (float) ((firstCtlLength) * Math.sin(degree* Math.PI/180 + Math.PI/N)); float rightX = (float) ((firstCtlLength) * Math.cos(degree* Math.PI/180 + Math.PI/N)); float topLeftY = leftY + (float) ( R/2f * Math.sin(degree* Math.PI/180)); //左侧第二控制点 float topLeftX = leftX + (float)( R/2f * Math.cos(degree* Math.PI/180)) ; float topRightY = rightY + (float) ( R/2f * Math.sin(degree* Math.PI/180)); //右侧第二控制点 float topRightX = rightX + (float)( R/2f * Math.cos(degree* Math.PI/180)) ; mPath.reset(); mPath.moveTo(0,0); mPath.cubicTo(leftX,leftY,topLeftX,topLeftY,endX,endY); mPath.cubicTo(topRightX,topRightY,rightX,rightY,0,0); mPath.close(); if(colorSet==null || colorSet.length==0) { mPaint.setColor(0x9aFB2222); }else{ mPaint.setColor(colorSet[pos%N]); } mPath.setFillType(Path.FillType.WINDING); mPaint.setStyle(Paint.Style.FILL); canvas.drawPath(mPath,mPaint); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.STROKE); canvas.drawPath(mPath,mPaint); } private synchronized void clearCanvas(Canvas canvas) { final Xfermode xfermode = mPaint.getXfermode(); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawPaint(mPaint); mPaint.setXfermode(xfermode); } public float dip2px(int dp){ return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics()); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); } public void setDegree(float degree) { this.degree = degree; invalidate(); }}

以上就是整个View的实现,使用方法如下

myFlower = (FlowerView) findViewById(R.id.id_myflower);        myFlower.setPetalNumber(7,null);        myFlower.setOnClickListener(this);    //省略其他不需要给你们看的代码    @Override    public void onClick(View v) {        if(v.getId()==R.id.id_myflower){            myFlower.startRotate();        }    }

 

 

 

转载于:https://my.oschina.net/ososchina/blog/3026885

你可能感兴趣的文章
java 设计模式-动态代理
查看>>
xml学习笔记(第二篇DTD)
查看>>
把U盘制作成多重启动盘并集成linux安装盘
查看>>
内存条对电脑的速度影响
查看>>
PostgreSQL锁查询与杀掉进程说明
查看>>
idea进行断点快捷键
查看>>
Windows 7远程管理Exchange2010
查看>>
cacti 监控linux TCP端口连接数
查看>>
Linux修改显示亮度
查看>>
lnmp+zabbix一键部署脚本
查看>>
其实你还不懂word
查看>>
vcSA修改IP或hostname
查看>>
写给刚入行的新人和技术控们
查看>>
python运维开发之socket网络编程02
查看>>
每次访问都生成不一样sessionId
查看>>
vmware esxi安装linux启动在Starting udev 停止
查看>>
AIX下NFS共享设置
查看>>
sersync 实现数据实时同步镜像
查看>>
HibernateTemplate的原理与hibernate三态
查看>>
awk学习笔记(1) - 简介及入门
查看>>