目录

  • 自定义View——游动锦鲤实践
    • 布局文件
    • 使用布局——MainAvtivity
    • 主要实现——FishDrawable

不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵!

自定义View——游动锦鲤实践

一个对于自定义View的尝试,主要用于尝试熟悉自定义View的实现过程,有些小瑕疵。

布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><ImageViewandroid:id="@+id/iv_fish"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>

使用布局——MainAvtivity

package com.hnucm.otherapp;import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ImageView ivFish = findViewById(R.id.iv_fish);ivFish.setImageDrawable(new FishDrawable());}
}

主要实现——FishDrawable

package com.hnucm.otherapp;import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.view.animation.LinearInterpolator;
import android.widget.HeaderViewListAdapter;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;/*** @author created by lvjunkai* @date 2021-09-27* @description: 实现一个自定义锦鲤的绘制*/
public class FishDrawable extends Drawable {//路径private Path mPath;//画笔private Paint mPaint;//身体外透明度private final static int OTHER_ALPHA = 110;//身体透明度private final static int BODY_ALPHA = 160;//鱼头半径,用于改变鱼的大小private final static int HEAD_RADIUS = 150;//坐标private PointF middlePoint;//鱼朝向private float fishMainAngle = 90;//鱼身长度private final static float BODY_LENGTH = 3.2f * HEAD_RADIUS;//寻找鱼鳍起点的线长private final static float FIND_FINS_LENGTH = 0.9f * HEAD_RADIUS;//鱼鳍的长度private final static float FINS_LENGTH = 1.3f * HEAD_RADIUS;//-------------鱼尾----------------//尾部大圆的半径(圆心就是身体底部的中点)private final static float BIG_CIRCLE_RADIUS = HEAD_RADIUS * 0.7f;//尾部中圆的半径private final static float MIDDLE_CIRCLE_RADIUS = BIG_CIRCLE_RADIUS * 0.6f;//尾部小圆的半径private final static float SMALL_CIRCLE_RADIUS = MIDDLE_CIRCLE_RADIUS * 0.4f;// --寻找尾部中圆圆心的线长private final static float FIND_MIDDLE_CIRCLE_LENGTH = BIG_CIRCLE_RADIUS + MIDDLE_CIRCLE_RADIUS;// --寻找尾部小圆圆心的线长private final static float FIND_SMALL_CIRCLE_LENGTH = MIDDLE_CIRCLE_RADIUS * (0.4f + 2.7f);// --寻找大三角形底边中心点的线长private final static float FIND_TRIANGLE_LENGTH = MIDDLE_CIRCLE_RADIUS * 2.7f;private float currentValue = 0;private float currentValue1 = 0;private float currentValue2 = 0;//构造函数,用于初始化drawablepublic FishDrawable(){init();}//初始化private void init(){mPath = new Path();//路径mPaint = new Paint();//画笔mPaint.setAntiAlias(true);//抗锯齿mPaint.setDither(true);//防抖mPaint.setStyle(Paint.Style.FILL);//画笔类型填充mPaint.setARGB(OTHER_ALPHA,244,92,71);//设置颜色//鱼重心的坐标middlePoint = new PointF(4.18f * HEAD_RADIUS,4.18f * HEAD_RADIUS);//属性动画ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,360);
//        ValueAnimator valueAnimator = ValueAnimator.ofFloat(-1,1);valueAnimator.setDuration(1000);
//        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);valueAnimator.setRepeatMode(ValueAnimator.RESTART);valueAnimator.setRepeatCount(ValueAnimator.INFINITE);valueAnimator.setInterpolator(new LinearInterpolator());valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animator) {currentValue = (float) animator.getAnimatedValue();invalidateSelf();}});valueAnimator.start();}//绘制@Overridepublic void draw(@NonNull Canvas canvas) {//        float fishAngle = fishMainAngle + currentValue * 20;
//        float fishAngle = fishMainAngle + currentValue * 10;float fishAngle = (float) (fishMainAngle + Math.sin(Math.toRadians(currentValue * 1)) * 10);//圆心PointF headPoint = calculatePoint(middlePoint,BODY_LENGTH / 2,fishAngle);//以圆心为中心,半径为HEAD_RADIUS,用画笔画圆canvas.drawCircle(headPoint.x,headPoint.y,HEAD_RADIUS,mPaint);//绘制右鱼鳍PointF rightFinsPoint = calculatePoint(headPoint,FIND_FINS_LENGTH,fishAngle - 110);makeFins(canvas,rightFinsPoint,fishAngle,true);//绘制左鱼鳍PointF leftFinsPoint = calculatePoint(headPoint,FIND_FINS_LENGTH,fishAngle + 110);makeFins(canvas,leftFinsPoint,fishAngle,false);//身体底部的中心点PointF bodyBottomCenterPoint = calculatePoint(headPoint,BODY_LENGTH,fishAngle - 180);//画节肢1
//        makeSegment(canvas,bodyBottomCenterPoint,BIG_CIRCLE_RADIUS,MIDDLE_CIRCLE_RADIUS,
//                FIND_MIDDLE_CIRCLE_LENGTH,fishAngle,true);PointF middleCircleCenterPoint = makeSegment(canvas,bodyBottomCenterPoint,BIG_CIRCLE_RADIUS,MIDDLE_CIRCLE_RADIUS,FIND_MIDDLE_CIRCLE_LENGTH,fishAngle,true);//画节肢2
//        PointF middleCircleCenterPoint = calculatePoint(bodyBottomCenterPoint,
//                FIND_MIDDLE_CIRCLE_LENGTH,fishAngle - 180);makeSegment(canvas,middleCircleCenterPoint,MIDDLE_CIRCLE_RADIUS,SMALL_CIRCLE_RADIUS,FIND_SMALL_CIRCLE_LENGTH,fishAngle,false);//画尾巴makeTriangle(canvas,middleCircleCenterPoint,FIND_TRIANGLE_LENGTH,BIG_CIRCLE_RADIUS,fishAngle);makeTriangle(canvas,middleCircleCenterPoint,FIND_TRIANGLE_LENGTH - 10,BIG_CIRCLE_RADIUS - 20,fishAngle);//画身体makeBody(canvas,headPoint,bodyBottomCenterPoint,fishAngle);}//绘制鱼鳍private void makeFins(Canvas canvas, PointF startPoint, float fishAngle,boolean isRightFins) {float controlAngle = 115;//二阶贝塞尔曲线的控制点坐标PointF controlPoint = calculatePoint(startPoint,1.8f * FINS_LENGTH,isRightFins ? fishAngle - controlAngle : fishAngle + controlAngle);//结束点坐标PointF endPoint = calculatePoint(startPoint,FINS_LENGTH,fishAngle - 180);mPath.reset();mPath.moveTo(startPoint.x,startPoint.y);mPath.quadTo(controlPoint.x,controlPoint.y,endPoint.x,endPoint.y);canvas.drawPath(mPath,mPaint);}//绘制节肢private PointF makeSegment(Canvas canvas,PointF bottomCenterPoint,float bigRadius,float smallRadius,float findSmallCircleLength,float fishAngle,boolean hasBigCircle){float segmentAngle;if(hasBigCircle){//            segmentAngle = fishAngle + currentValue * 30;segmentAngle = (float) (fishAngle + Math.sin(Math.toRadians(currentValue * 2)) * 30);}else{//            segmentAngle = fishAngle + currentValue * 50;segmentAngle = (float) (fishAngle + Math.sin(Math.toRadians(currentValue * 3)) * 50);}//梯形上底的中心点(中等大的圆的圆心)
//        PointF upperCenterPoint = calculatePoint(bottomCenterPoint,findSmallCircleLength,
//                fishAngle - 180);PointF upperCenterPoint = calculatePoint(bottomCenterPoint,findSmallCircleLength,segmentAngle - 180);//梯形的四个点
//        PointF bottomLeftPoint = calculatePoint(bottomCenterPoint,bigRadius,fishAngle + 90);
//        PointF bottomRightPoint = calculatePoint(bottomCenterPoint,bigRadius,fishAngle - 90);
//        PointF upperLeftPoint = calculatePoint(upperCenterPoint,smallRadius,fishAngle + 90);
//        PointF upperRightPoint = calculatePoint(upperCenterPoint,smallRadius,fishAngle - 90);PointF bottomLeftPoint = calculatePoint(bottomCenterPoint,bigRadius,segmentAngle + 90);PointF bottomRightPoint = calculatePoint(bottomCenterPoint,bigRadius,segmentAngle - 90);PointF upperLeftPoint = calculatePoint(upperCenterPoint,smallRadius,segmentAngle + 90);PointF upperRightPoint = calculatePoint(upperCenterPoint,smallRadius,segmentAngle - 90);if(hasBigCircle){//画大圆canvas.drawCircle(bottomCenterPoint.x,bottomCenterPoint.y,bigRadius,mPaint);}//画小圆canvas.drawCircle(upperCenterPoint.x,upperCenterPoint.y,smallRadius,mPaint);//画梯形mPath.reset();mPath.moveTo(bottomLeftPoint.x,bottomLeftPoint.y);mPath.lineTo(upperLeftPoint.x,upperLeftPoint.y);mPath.lineTo(upperRightPoint.x,upperRightPoint.y);mPath.lineTo(bottomRightPoint.x,bottomRightPoint.y);canvas.drawPath(mPath,mPaint);//绘制节肢2和三角形的起始点,必须在这儿返回return upperCenterPoint;}//绘制尾巴private void makeTriangle(Canvas canvas, PointF startPoint,float findCenterLength,float findEdgeLength,float fishAngle){//三角形底边的中心点PointF centerPoint = calculatePoint(startPoint,findCenterLength,fishAngle - 180);//三角形底边的两点PointF leftPoint = calculatePoint(centerPoint,findEdgeLength,fishAngle + 90);PointF rightPoint = calculatePoint(centerPoint,findEdgeLength,fishAngle - 90);//绘制三角形mPath.reset();mPath.moveTo(startPoint.x,startPoint.y);mPath.lineTo(leftPoint.x,leftPoint.y);mPath.lineTo(rightPoint.x,rightPoint.y);canvas.drawPath(mPath,mPaint);}//绘制身体private void makeBody(Canvas canvas,PointF headPoint,PointF bodyBottomCenterPoint,float fishAngle){//身体的四个点PointF topLeftPoint = calculatePoint(headPoint,HEAD_RADIUS,fishAngle + 90);PointF topRightPoint = calculatePoint(headPoint,HEAD_RADIUS,fishAngle - 90);PointF bottomLeftPoint = calculatePoint(bodyBottomCenterPoint,BIG_CIRCLE_RADIUS,fishAngle + 90);PointF bottomRightPoint = calculatePoint(bodyBottomCenterPoint,BIG_CIRCLE_RADIUS,fishAngle - 90);// 二阶贝塞尔曲线的控制点,决定鱼的胖瘦PointF controlLeft = calculatePoint(headPoint,BODY_LENGTH * 0.56f,fishAngle + 130);PointF controlRight = calculatePoint(headPoint,BODY_LENGTH * 0.56f,fishAngle - 130);//画身体mPath.reset();mPath.moveTo(topLeftPoint.x,topLeftPoint.y);mPath.quadTo(controlLeft.x,controlLeft.y,bottomLeftPoint.x,bottomLeftPoint.y);mPath.lineTo(bottomRightPoint.x,bottomRightPoint.y);mPath.quadTo(controlRight.x,controlRight.y,topRightPoint.x,topRightPoint.y);mPaint.setAlpha(BODY_ALPHA);canvas.drawPath(mPath,mPaint);}//计算公式  传入起始点坐标,给出两点之间的长度,两点连线和x坐标的夹角,求出点的坐标public static PointF calculatePoint(PointF startPoint,float length,float angle){float deltaX = (float) (Math.cos(Math.toRadians(angle)) * length);float deltaY = (float) (Math.sin(Math.toRadians(angle - 180)) * length);return new PointF(startPoint.x + deltaX,startPoint.y + deltaY);}//设置透明度@Overridepublic void setAlpha(int alpha) {mPaint.setAlpha(alpha);}//设置颜色过滤器@Overridepublic void setColorFilter(@Nullable ColorFilter colorFilter) {mPaint.setColorFilter(colorFilter);}//设置alpha值@Overridepublic int getOpacity() {return PixelFormat.TRANSLUCENT;}//宽@Overridepublic int getIntrinsicWidth() {return (int) (8.38f * HEAD_RADIUS);}//高@Overridepublic int getIntrinsicHeight() {return (int) (8.38f * HEAD_RADIUS);}
}

自定义View——游动锦鲤实践相关推荐

  1. android 动画之漂移,[超棒]自定义View居然还能这样?用 Android 实现一条小金鱼游动动画...

    原标题:[超棒]自定义View居然还能这样?用 Android 实现一条小金鱼游动动画 前言 此篇中的小鱼动画是模仿国外一个大牛做的flash动画,第一眼就爱上它了,简约灵动又不失美学,于是抽空试着尝 ...

  2. android绘制心形_Android自定义View系列(一)——打造一个爱心进度条

    写作原因:Android进阶过程中有一个绕不开的话题--自定义View.这一块是安卓程序员更好地实现功能自主化必须迈出的一步.下面这个系列博主将通过实现几个例子来认识安卓自定义View的方法.从自定义 ...

  3. Android Paint应用之自定义View实现进度条控件

    在上一篇文章<Android神笔之Paint>学习了Paint的基本用法,但是具体的应用我们还没有实践过.从标题中可知,本文是带领读者使用Paint,自定义一个进度条控件. 上图就是本文要 ...

  4. Android 高级自定义View实战

    2019独角兽企业重金招聘Python工程师标准>>> 在android组件中主要分为两种:容器(LinearLayout....)和子View(TextView......),但是 ...

  5. android覆盖扩散动画,[Android]多层波纹扩散动画——自定义View绘制

    之前整理过一些属性动画的基本操作,这一段时间的动画相关需求都安然度过了.直到这次-- 一.另一种动画需求 多数交互中的动画都是让单个页面元素动起来,这种就很适合用属性动画实现.但是对于 多个元素.非页 ...

  6. 推翻自己和过往,重学自定义View

    http://blog.csdn.net/lfdfhl/article/details/51671038 深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 A ...

  7. Android 系统(201)---Android 自定义View实战系列 :时间轴

    Android 自定义View实战系列 :时间轴 Android开发中,时间轴的 UI需求非常常见,如下图: 本文将结合 自定义View & RecyclerView的知识,手把手教你实现该常 ...

  8. 自定义View以及事件分发总结

    一些零碎的知识的. 坐标系原点默认是屏幕左上角,向右为X轴正方向,向下为Y轴正方向. View的getTop().getLeft().getBottom().getRight()是相对父View来说的 ...

  9. 听歌识曲java_Android自定义View之继承扩展(仿网易云音乐听歌识曲)

    前言 上篇文章说到了自定义View的组合实战,链接:Android自定义View之组合实战(以支付宝页面为例) ,感兴趣的同学可以看看.今天要分享的是一个模仿网易云音乐听歌识曲界面的自定义View,实 ...

最新文章

  1. 后端工程师入门前端页面重构(二):心法 I
  2. OpenCV运行自定义OCR模型
  3. 如何梳理产品功能,才能既见森林又见树木?
  4. Java快速入门学习笔记8 | Java语言中的数组
  5. 斗地主AI算法——第三章の数据处理
  6. pip慢?半分钟解决方案
  7. 编辑中的word变成只读_打开Word文件是只读,怎么修改
  8. lbp2900linux驱动下载,佳能lbp2900打印机驱动下载|佳能lbp2900打印机驱动下载 通用版_小皮网...
  9. ruoyi-ui下载依赖报错npm ERR! cb() never called!
  10. 5分钟超快速写,快写练习讲究快准狠~
  11. ctfshow crypto funnyrsa3 RSA之dp泄露
  12. Hibernate对原生sql处理及结果集和VO的映射
  13. 使用 SimpleWebRTC 构建 WebRTC 视频聊天应用程序
  14. 智能工厂方案与设备选型
  15. 桌面图标点不开服务器运行失败,桌面图标打不开的解决技巧
  16. “GANs”与“ODEs”:数学建模的终结?
  17. 什么是 APT 攻击?
  18. Docker玩腻了,不妨试试用Vagrant
  19. 亿图脑图MindMaster(Pro)
  20. excel 进行二叉树_基础扩展 | 20. 建立二叉树

热门文章

  1. 直播系统源码,使用python批量生成原比例缩略图
  2. python调用google提供的的客户端方式进行翻译
  3. SCAFFOLD: Stochastic Controlled Averaging for Federated Learning学习
  4. 行人重识别0-08:DG-Net(ReID)-代码无死角解读(4)-网络Es编码解码过程
  5. dwg格式CAD图纸转换成PDF格式
  6. 小米 信号测试软件,小米MIX 3信号实测:完胜iPhone XS Max
  7. 瑞萨RX72M E2Studio开发笔记2 输出PWM
  8. (附源码)SSM医院药品进销存系统JAVA计算机毕业设计项目
  9. Postman的女朋友Postwoman来了:太酷了
  10. 团队IM工具BearyChat 获千万级 A 轮融资,华诺创投领投