如何应对Android面试官->实战高级UI,用自定义View画一条锦鲤(上)

Qt之使用QGraphicsEffect实现阴影、模糊、着色和透明效果 QGraphicsEffect是所有图像特效的子类,其四个子类分别提供了四种标准特效 ☆QGraphicsBlurEffect - blurs the item by a given radius ☆QGraphicsDropShadowEffect - renders a dropshadow behind the item ☆QGraphicsColorizeEffect - renders the item in shades of any given color ☆QGraphicsOpacityE 阅读详情

前言


如何用自定义View画一条鱼,其中涉及到哪些知识点?我们先上效果图:

8cfdce80-765e-4730-936a-56c4e967d22c.gif

涉及的知识点:

infoflow 2024-02-05 10-32-59.png

整体可以分为三大步骤

  1. 小鱼的绘制
  2. 小鱼的摆动
  3. 点击之后小鱼的游动

小鱼的绘制


想实现小鱼的绘制,我们首先需要分解下这个小鱼都由哪些组成

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

整体可以分成 头、鱼鳍、身体、节肢1、节肢2、尾巴 六大部分组成,我们接下来分别进行绘制;

绘制整条小鱼,我们今天使用一个自定义 Drawable 来完成,继承 Drawable 需要实现下面四个方法;

public class Fish extends Drawable {

    @Override
    public void draw(@NonNull Canvas canvas) {

    }

    /**
     * 设置透明度
     * @param canvas The canvas to draw into 
     */
    @Override
    public void setAlpha(int alpha) {

    }

    /**
     * 设置颜色过滤器,在绘制出来之前,被绘制的内容的每一个像素都会被颜色过滤器改变
     * @param colorFilter The color filter to apply, or {@code null} to remove the 
     *                    existing color filter
     */
    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {

    }
    
    /**
     * 这个值,可以根据 setAlpha 中设置的值进行调整,比如,alpha == 0 的时候设置为 PixelFormat.TRANSPARENT。
     * 在alpha == 255 时这是为 PixelFormat.OPAQUE。在其他时候设置为 PixelFormat.TRANSLUCENT。
     * PixelFormat.OPAQUE 完全不透明,遮盖在它下面的所有内容上
     * PixelFormat.TRANSPARENT 透明,完全不显示任何东西
     * PixelFormat.TRANSLUCENT 只有绘制的地方才覆盖底下的内容
     * @return PixelFormat.TRANSLUCENT
     */
    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
}

自定义View 自然少不了 Paint 和 Path,我们来初始化这两个对象;Path 和 Paint 这两个类不做过多解释了,不了解的同学可以看下扔物线对这两个的解释,比较详细;

public Fish() {
    init();
}

/**
 * 初始化
 */
private void init() {
    mPath = new Path();
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setStyle(Paint.Style.FILL);
    mPaint.setDither(true);
    mPaint.setARGB(110, 244, 92, 71);
}

接下来,我们开始绘制鱼

计算小鱼的宽高

计算小鱼的宽高,我们需要以小鱼的中心点为起点,小鱼的尾部为终点,计算个距离,然后 x2,因为我们的小鱼是可以旋转的,以中心为圆点的话,那么最长半径的2倍,才能完整的放下我们这条小鱼;

小鱼的鱼头是圆的,那么半径就可以我们自己定义,然后根据鱼头的半径我们来计算各个位置的大小,总体的一个计算结果如下:

infoflow 2024-02-05 11-16-17.png

可以看到,鱼的中心点位置到鱼尾的距离是 4.19R;所以整个鱼的宽高就是 4.192R = 8.38R;然后 Drawable 也提供了一个设置宽高的方法;

当然了 这些值都是自己可以定义的,只要你画出的鱼符合设计的要求即可;

private static final float HEAD_RADIUS = 150f;

@Override
public int getIntrinsicHeight() {
    return (int) (8.38 * HEAD_RADIUS);
}

@Override
public int getIntrinsicWidth() {
    return (int) (8.38 * HEAD_RADIUS);
}

确定小鱼的中心

前面说到了,整个鱼的宽高就是 4.192R = 8.38R,所以小鱼的中心就是 4.19R;

private PointF pointF;

private void init() {
    pointF = new PointF((4.19f * HEAD_RADIUS), (4.19f * HEAD_RADIUS));
}

绘制鱼头

我们可以找到小鱼的中心点位置,那么我们就可以根据中心位置来计算鱼头的中心点坐标,然后以这个坐标画一个圆,那么鱼头的中心点坐标怎么计算呢?

infoflow 2024-02-05 14-16-44.png

假设我们以小鱼的中心为(0, 0)点,那么当鱼旋转到X正轴方向上的时候,鱼头圆心位置就是(2.6R, 0)当鱼旋转到蓝色线的位置的时候,那么我们只需要计算出鱼头圆心的位置点坐标,那么不管这条鱼怎么旋转,我们都能获取到这个鱼头的圆心坐标,我们来看下怎么计算?

这里就用到了我们初中学习的三角函数

infoflow 2024-02-05 14-21-32.png

我们如果想要求 B 的坐标,也就 『对边a』和『邻边b』的长度,根据勾股定理可以知道

a = sinA * 斜边c

b = cosA * 斜边c

这样我们就能获取 B 的坐标(b,a)另外,在 Android 坐标系中『下正上负』,和数学中的坐标不一样(上正下负),所以我们需要一个取反操作,一种是直接加一个负号,一种是角度 - 180,最终的计算逻辑如下:

/**
 * 计算点位函数
 *
 * @param startPoint 起始点
 * @param length 起始点到终点的距离
 * @param angle 起始点和终点的角度
 */
private PointF calculatePoint(PointF startPoint, int length, int angle) {
    // X 轴坐标 也就是临边 b 的长度 b = cosA * 斜边 c
    float deltaX = (float) (Math.cosh(Math.toRadians(angle)) * length);
    // Y 轴坐标 也就是对边 a 的长度 a = sinA * 斜边 c
    float deltaY = (float) (Math.sin(Math.toRadians(angle - 180)) * length);
    return new PointF(startPoint.x + deltaX, startPoint.y + deltaY);
}

然后我们来画鱼头

// 初始角度
private float fishMainAngle = 0f;
// 鱼头半径
private static final float HEAD_RADIUS = 150f;
// 鱼身体长度
private final float FISH_BODY_LENGTH = HEAD_RADIUS * 3.2f;

@Override
public void draw(@NonNull Canvas canvas) {
    float fishAngle = fishMainAngle;
    // 鱼头的圆心坐标
    PointF fishHeadPoint = calculatePoint(middlePointF, FISH_BODY_LENGTH / 2f, fishAngle);
    // 画鱼头
    canvas.drawCircle(fishHeadPoint.x, fishHeadPoint.y, HEAD_RADIUS, mPaint);
}

我们运行看下效果:

infoflow 2024-02-05 15-12-14.png

鱼头已经画了出来;

绘制鱼鳍

鱼鳍的绘制,这里应用到了二阶贝塞尔曲线,起点,终点,以及控制点

infoflow 2024-02-05 15-15-24.png

所以鱼鳍的绘制,我们只需要找出这三个点就可以了;鱼鳍的位置可以相对鱼头来画,这样的话我们就依赖鱼头的圆心点坐标来计算,因为鱼鳍是两个,我们分为左鱼鳍和右鱼鳍;

鱼鳍的坐标计算方式如下:

infoflow 2024-02-05 15-28-03.png

@Override
public void draw(@NonNull Canvas canvas) {
    // 画鱼鳍
    // 鱼鳍的起始点坐标
    PointF rightFinsPoint = calculatePoint(fishHeadPoint, FISH_FINS_LENGTH, fishAngle - 110);
    makeFins(canvas, rightFinsPoint, fishAngle);
}

makeFins 画鱼鳍的逻辑

/**
 * 画鱼鳍
 *
 * @param canvas 画布
 * @param startPoint 鱼鳍坐标
 * @param fishAngle 鱼鳍的角度
 */
private void makeFins(Canvas canvas, PointF startPoint, float fishAngle) {
    // 控制点的弧度,用来计算控制点的坐标
    float controlAngle = 115;
    // 鱼鳍的结束点坐标
    PointF endPoint = calculatePoint(startPoint, FINS_LENGTH, fishAngle - 180);
    // 鱼鳍的控制点坐标
    PointF controlPoint = calculatePoint(startPoint, FINS_CONTROL_LENGTH, fishAngle - controlAngle);
    // 绘制
    mPath.reset();
    // 画笔移动到起始点
    mPath.moveTo(startPoint.x, startPoint.y);
    // 绘制二阶贝塞尔曲线,需要传入的是 控制点坐标和结束点坐标
    mPath.quadTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
    canvas.drawPath(mPath, mPaint);
}

我们运行看下效果:

infoflow 2024-02-05 16-22-06.png

可以看到,我们的鱼鳍绘制了出来,接下来我们来绘制左鱼鳍,左鱼鳍其实和右的绘制逻辑是一样的,只是坐标抽取反即可;

@Override
public void draw(@NonNull Canvas canvas) {
    // 画鱼鳍
    // 鱼鳍的起始点坐标
    PointF rightFinsPoint = calculatePoint(fishHeadPoint, FISH_FINS_LENGTH, fishAngle - 110);
    makeFins(canvas, rightFinsPoint, fishAngle, true);
    
    PointF leftFinsPoint = calculatePoint(fishHeadPoint, FISH_FINS_LENGTH, fishAngle + 110);
    makeFins(canvas, leftFinsPoint, fishAngle, false);
}

然后我们需要修改下控制点的坐标,也是对称取反,我们这里使用一个标志位,是画左还是右;

/**
 * 画鱼鳍
 *
 * @param canvas 画布
 * @param startPoint 鱼鳍坐标
 * @param fishAngle 鱼鳍的角度
 */
private void makeFins(Canvas canvas, PointF startPoint, float fishAngle, boolean isRight) {
    // 控制点的弧度,用来计算控制点的坐标
    float controlAngle = 115;
    // 鱼鳍的结束点坐标
    PointF endPoint = calculatePoint(startPoint, FINS_LENGTH, fishAngle - 180);
    // 鱼鳍的控制点坐标,这里根据标志位来判断是不是要取反
    PointF controlPoint = calculatePoint(startPoint, FINS_CONTROL_LENGTH, isRight ? fishAngle - controlAngle : fishAngle + controlAngle);
    // 绘制
    mPath.reset();
    // 画笔移动到起始点
    mPath.moveTo(startPoint.x, startPoint.y);
    // 绘制二阶贝塞尔曲线,需要传入的是 控制点坐标和结束点坐标
    mPath.quadTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
    canvas.drawPath(mPath, mPaint);
}

我们运行看下效果:

infoflow 2024-02-05 16-28-29.png

左边的鱼鳍我们也绘制了出来;

画节肢

画节肢,分为三部分,两个圆和一个梯形,我们先求身体底部中心点坐标,还是以鱼头圆心为参照点

PointF bodyBottomCenterPoint = calculatePoint(headPoint, FISH_BODY_LENGTH, fishAngle - 180);

然后我们来绘制梯形,梯形的绘制,我们也是画线,我们需要获取梯形四个点的坐标,以及两个圆的中心点坐标

infoflow 2024-02-05 16-42-12.png

/**
 * 画节肢
 * @param canvas 画布
 * @param bottomCenterPoint 大圆中心点坐标
 * @param fishAngle 角度
 */
private void makeSegment(Canvas canvas, PointF bottomCenterPoint, float fishAngle) {

    // 计算中圆坐标(梯形上底圆的圆心)
    PointF upperCenterPoint = calculatePoint(bottomCenterPoint, FIND_MIDDLE_CIRCLE_LENGTH, fishAngle - 180);
    // 计算梯形的四个点
    PointF bottomLeftPoint = calculatePoint(bottomCenterPoint, BIG_CIRCLE_RADIUS, fishAngle + 90);
    PointF bottomRightPoint = calculatePoint(bottomCenterPoint, BIG_CIRCLE_RADIUS, fishAngle - 90);
    PointF upperLeftPoint = calculatePoint(upperCenterPoint, MIDDLE_CIRCLE_RADIUS, fishAngle + 90);
    PointF upperRightPoint = calculatePoint(upperCenterPoint, MIDDLE_CIRCLE_RADIUS, fishAngle - 90);
    // 画大圆
    canvas.drawCircle(bottomCenterPoint.x, bottomCenterPoint.y, BIG_CIRCLE_RADIUS, mPaint);
    // 画小圆
    canvas.drawCircle(upperCenterPoint.x, upperCenterPoint.y, MIDDLE_CIRCLE_RADIUS, mPaint);
    // 画梯形
    mPath.reset();
    mPath.moveTo(upperLeftPoint.x, upperLeftPoint.y);
    mPath.lineTo(upperRightPoint.x, upperRightPoint.y);
    mPath.lineTo(bottomRightPoint.x, bottomRightPoint.y);
    mPath.lineTo(bottomLeftPoint.x, bottomLeftPoint.y);
    canvas.drawPath(mPath, mPaint);
}

我们运行看下效果:

infoflow 2024-02-05 16-54-33.png

我们画出了两个圆和一个梯形;我们接下来画第二个节肢,第二个节肢和第一个比较类似,它是一个圆形,一个梯形;

infoflow 2024-02-06 17-06-30.png

我们可以利用我们前面写的 makeSegment 方法来画节肢2,我们将相关常量值提取出来

private PointF makeSegment(Canvas canvas, PointF bottomCenterPoint, float bigRadius, float smallRadius,
                           float findSmallCircleLength, float fishAngle, boolean hasBigCircle) {
    // 相关常量值进行替换,以及节肢1的大圆只在画节肢1的时候才执行,增加一个 hasBigCircle 的标志位
    PointF upperCenterPoint = calculatePoint(bottomCenterPoint, findSmallCircleLength,
            fishAngle - 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);

    if (hasBigCircle) {
        // 画大圆 --- 只在节肢1 上才绘画
        canvas.drawCircle(bottomCenterPoint.x, bottomCenterPoint.y, bigRadius, mPaint);
    }
    // 画小圆
    canvas.drawCircle(upperCenterPoint.x, upperCenterPoint.y, smallRadius, mPaint);

    // 画梯形
    mPath.reset();
    mPath.moveTo(upperLeftPoint.x, upperLeftPoint.y);
    mPath.lineTo(upperRightPoint.x, upperRightPoint.y);
    mPath.lineTo(bottomRightPoint.x, bottomRightPoint.y);
    mPath.lineTo(bottomLeftPoint.x, bottomLeftPoint.y);
    canvas.drawPath(mPath, mPaint);

    return upperCenterPoint;   
}

// 以节肢的底圆中心为参照点
PointF middlePointF = makeSegment(canvas, bodyBottomCenterPoint, FIND_MIDDLE_CIRCLE_LENGTH, BIG_CIRCLE_RADIUS, MIDDLE_CIRCLE_RADIUS, fishAngle, true);
//
makeSegment(canvas, middlePointF, MIDDLE_CIRCLE_RADIUS, SMALL_CIRCLE_RADIUS,
        FIND_SMALL_CIRCLE_LENGTH, fishAngle, false);

// 画节肢2
makeSegment(canvas, middlePointF, MIDDLE_CIRCLE_RADIUS, SMALL_CIRCLE_RADIUS,
        FIND_SMALL_CIRCLE_LENGTH, fishAngle, false);

我们运行看下效果:

infoflow 2024-02-06 17-19-51.png

可以看到 节肢2 也绘制了出来了;

画尾巴

我们接下来画鱼的尾巴,尾巴就是两个三角形叠在一起,一个大的,一个小的,以中圆的圆心(middlePointF)为参照点,绘制一个三角形,中圆的圆心我们提前也已经拿到了;三角形也是使用 Path 来画线;

private void makeTriangle(Canvas canvas, PointF startPoint, float fishAngle) {
    // 三角形底边中心点坐标
    PointF centerPoint = calculatePoint(startPoint, FIND_TRIANGLE_LENGTH, fishAngle);
    // 三角形底边两点
    PointF leftPoint = calculatePoint(centerPoint, BIG_CIRCLE_RADIUS, fishAngle + 90);
    PointF rightPoint = calculatePoint(centerPoint, BIG_CIRCLE_RADIUS, 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);
}

我们运行看下效果

infoflow 2024-02-08 09-53-56.png

大三角画出来了,我们来画小三角,小三角其实就是半径小点和中轴线短一些,中心点一样,所以我们把这个方法抽取下;

private void makeTriangle(Canvas canvas, PointF startPoint, float findTriangleLength,
                          float bigCircleRadius, float fishAngle) {
    // 三角形底边中心点坐标
    PointF centerPoint = calculatePoint(startPoint, findTriangleLength, fishAngle);
    // 三角形底边两点
    PointF leftPoint = calculatePoint(centerPoint, bigCircleRadius, fishAngle + 90);
    PointF rightPoint = calculatePoint(centerPoint, bigCircleRadius, 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);
}
makeTriangle(canvas, middlePointF, FIND_TRIANGLE_LENGTH, BIG_CIRCLE_RADIUS, fishAngle);
makeTriangle(canvas, middlePointF, FIND_TRIANGLE_LENGTH - 10,
        BIG_CIRCLE_RADIUS - 20, fishAngle);

运行看下效果:

infoflow 2024-02-08 09-59-40.png

第二个三角形我们也绘制了出来,我们接下来绘制鱼的身体;

绘制鱼身体

鱼的身体绘制,其实左右两边各是一条二阶贝塞尔曲线,所以我们来绘制两条贝塞尔曲线,大圆和中圆的的圆心点我们也已经获取到了,我们可以求出身体的四个点,topLeft,topRight,bottomLeft,bottomRight;

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);
}

我们运行看小效果:

infoflow 2024-02-08 10-07-10.png

OK,到这里,我们的这条鱼就画完了,一条完美的锦鲤呈现在我们眼前;

好了,鱼的绘制就到这里吧,我们下一章来让我们的小鱼动起来;

下一章预告

小鱼游动

欢迎三连

来都来了,点个关注,点个赞吧,你的支持是我最大的动力;

android自定义炫酷UI-灵动的锦鲤 通过自定义android高级UI实现了一种类似小鱼游泳的炫酷效果,自定义drawable、自定义layout、属性动画的使用、点击事件的处理、水波纹效果、贝塞尔曲线的使用等等,实现的小鱼不仅会动,还能根据鼠标点击的位置进行游动,十分灵动! 立即下载

相关推荐

自定义View_灵动的锦鲤

自定义View_灵动的锦鲤

Android UI实践 —— 游动的锦鲤

看文章时无意间发现了一个很有趣的动画效果,于是自己动手实现了一下。

tmacfrank 1061

自定义Drawable实现灵动的红鲤鱼动画

自定义Drawable实现灵动的红鲤鱼动画,附:算法计算。

如何应对Android面试官->实战高级UI,用自定义View画一条锦鲤(下)

自定义View绘制锦鲤(下),让小鱼游动起来~~~

IT_Android的博客 1240

(UE4 4.27) HISM性能优化:从空间剔除到合批渲染的实战解析

本文深入解析了UE4 4.27中HISM(UHierarchicalInstancedStaticMesh)组件的性能优化原理与实战技巧。核心在于利用其N叉树空间结构实现高效的CPU视锥剔除,并结合GPU实例化进行合批渲染。文章详细探讨了从控制叶子节点粒度、平衡剔除精度与渲染效率,到结合LOD系统等关键参数的调优方法,为开放世界或大场景的植被性能瓶颈提供了系统解决方案。

weixin_29015051的博客 327

Spring AI 实战:5 分钟搭建你的第一个 AI 应用(含完整代码)

能力关键 API适用场景基础对话简单问答、文本生成流式输出实时打字机效果@Bean模型需要调用外部工具结构化输出需要返回 Java 对象多轮对话聊天机器人场景Spring AI 让 Java 开发者可以用最熟悉的方式(Spring Boot + Maven)进入 AI 应用开发领域,不用学新语言,不用换框架,这是它最大的优势。但目前为止,我们的 AI 应用只能回答"它脑子里已有的知识"。如果让它读懂你自己的技术文档、公司内部知识库呢?这就是下一篇文章的主题——RAG(检索增强生成)实战。

qq_17204557的博客 642

android自定义Drawable实现炫酷UI-锦鲤游泳效果

一、实现效果: 当点击屏幕的时候,屏幕中的锦鲤会身体摆动并且游到屏幕点击处,如下图: 效果分析: 1、小鱼的身体各个部件都是简单的半透明几何图形。 2、各个部件都可以活动。 3、从头到尾方向的部件摆动幅度越来越大,频率越来越高。 二、实现思路: 1、实现小鱼的绘制,创建一个自定义Drawable,把小鱼的形状画出来,然后放到ImageView上面显示。 2、实现小鱼的原地摆动,让小鱼可以在原地摆动。 3、实现小鱼的点击游动。 三、自定义Drawable 1、drawable

Jesiah的博客 3326

别再瞎试了!用Python+正交设计,5分钟搞定你的多因素实验方案

本文介绍了如何利用Python和正交设计高效优化多因素实验方案。正交设计通过精心设计的正交表,用最少的实验次数覆盖所有因素的水平组合,显著提升实验效率。文章详细讲解了正交设计的核心优势、Python实现工具链、实验实施与数据分析方法,以及高级技巧与常见问题解决方案,帮助读者快速掌握这一强大的实验优化技术。

weixin_42526087的博客 332

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

目录自定义View——游动锦鲤实践布局文件使用布局——MainAvtivity主要实现——FishDrawable 不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵! 自定义View——游动锦鲤实践 一个对于自定义View的尝试,主要用于尝试熟悉自定义View的实现过程,有些小瑕疵。 布局文件 <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.Constrain

小叮当不懒的博客 806

VxWorks系列 快速导航

Vxworks系列快速阅览导航

Mr.Sugarcane 1308

[Research Tips] 我的zotero文献管理方案: 云端同步+iPad批注+overleaf笔记

文献管理一直是一个很头疼的事. 最初直接在paper上做笔记, 后来尝试各种各样的文献管理软件, 比如endnote, mendeley等, 再后来直接用excel. 每一种方案都不是很满意. 最近尝试了各种软件, 摸索出一个合适自己的文献管理方案, 分享给大家. 我的需求: 支持PDF内全文搜索. 支持笔记搜索. 支持同步 可以批注PDF. 支持word内引用 支持Tex笔记语法 支持标签化管理 目前的方案除了第二个需求, 其他的都支持. 就目前我的经验来说, 除了知网研学可以搜索笔记外, 其他软件都

落日之城 5314

Android用自定义View画小猪佩奇

Android 自定义View 小猪佩奇

You_cx的博客 464

PCB_Project.PrjPcb 4 Not in version control

Altium Designer中PCB项目出现"NOT in version control"错误的解决方法:1. 禁用不需要的版本控制集成(DXP→Preferences→Version Control);2. 清理项目缓存(Projects面板右键→Clean Project);3. 检查文件读写权限;4. 如无效可新建项目重新添加文件。如需使用SVN版本控制,需正确配置SVN客户端路径,创建或连接SVN仓库,并将项目文件提交至版本控制系统。注意新建SVN仓库必须使用空目录,建议使用

whm128的博客 1592

Android自定义view详解,使用实例,自定义属性,贝塞尔曲线

前言 自定义View原理是Android开发者必须了解的基础; 在了解自定义View之前,你需要有一定的知识储备; 本文将全面解析关于自定义View中的所有知识基础。 目录 1. View的分类 视图View主要分为两类: 类别 解释 特点 单一视图 即一个View,如TextView 不包含子View 视图组 即多个View组成的ViewGr...

meixi_android的博客 3638

用 SAP-ABAP-1 把 ABAP 代码读懂:从 Generative AI Hub Orchestration 到 Joule 落地的实战指南

SAP-ABAP-1 是 SAP 推出的 ABAP 专用基础模型,专注于代码解释与理解。它能显著降低企业遗留系统的维护成本,帮助开发人员快速掌握复杂业务逻辑。该模型通过 SAP Generative AI hub 托管,支持 128,000 tokens 的上下文长度,适合分析大型 ABAP 类和 CDS 视图。典型应用场景包括代码解释、迁移辅助和云合规检查。调用需通过 Orchestration service 进行,确保企业级安全治理。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1211

【AI】获取各类AI大模型api-key的快速教程(OpenAI、Gemini、Claude、DeepSeek)

【AI】获取各类AI大模型api-key的快速教程(OpenAI、Gemini、Claude、DeepSeek)

funfan的博客 2929

从0开始搞一个锦鲤游动——动起来

上一篇文章主要讲了如何绘制一条锦鲤,而今天这篇文章,就讲如何让我们的锦鲤动起来。这次需要写一些比较复杂的算法,与数学关系很大,个别地方可能难以理解。不过大家可以多看两遍仔细斟酌,如果还是不理解的话可以来评论区交流。 效果展示 一.属性动画(ValueAnimator) 1.属性动画ValueAnimator介绍 ①ValueAnimator没有重绘,所以需要自己调用addUpdateListener方法,需要结合AnimatorUpdateListener使用 ②操作的对象的属性不一定要有getter和s

Android小白 1268

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Android --- 实现自定义View绘制动画——游动的小鱼

【Android自定义游动的锦鲤】自定义绘制一条可以游动的锦鲤,手指点击时,产生水波纹扩散效果,锦鲤可以游动到手指点击的位置,并且游动时摆动加快,效果逼真 GitHub资源地址: Smart_Koi

zjcoming 649

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

可拖动的圆形进度条

效果图如下: 1,通过继承View,重写onDraw(Canvas canvas)方法,实现界面进度显示 2,重写onTouchEvent(MotionEvent event)方法,监听拖动事件 3,在监听位置改变时,计算角度,重新调用onDraw()方法进行绘制 关键代码如下: public class MusicProgressBar extends View

技术笔记 4923

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

使用SurfaceView完成地图无缝拼接

随时随地阅读更多技术实战干货,获取项目源码、学习资料,请关注源代码社区公众号(ydmsq666) 本示例主要练习SurfaceView的使用和实现地图无缝拼接的算法,这在一些小游戏中非常常见,触碰屏幕可以绘制各种角色,如果在里面在添加一些怪物,便可以完成一个简单的小游戏,代码如下: MainActivity:...

孤云博客 3598

实现锦鲤动画

锦鲤动画 分析效果: 小鱼的身体各个部件都是简单的半透明几何图形 各个部件都可以活动 从头到尾方向的部件摆动幅度越来越大、频率越来越高 实现步骤: 实现小鱼的绘制 实现小鱼的原地摆动 实现小鱼点击游动 分解图 Drawable是什么? 一种可以在Canvas上进行绘制的抽象的概念 颜色、图片等都可以是一个Drawable Drawable可以通过XML定义,或者通过代码创建 Android中Drawable是一个抽象类,每个具体的Drawable都是其子类 Drawable的优点

qq_30621333的博客 458

android开发 鱼动画,自定义Drawable实现灵动的红鲤鱼动画(上篇)

此篇中的小鱼动画是模仿国外一个大牛做的flash动画,第一眼就爱上它了,简约灵动又不失美学,于是抽空试着尝试了一下,如下是我用Android实现的效果图:小鱼儿由于整个绘制分析过程比较繁琐所以灵动的红鲤鱼准备做成上下两篇,本篇是小鱼儿绘制的实现篇,第二篇是小鱼儿游动控制篇下篇传送门。本篇实现如下效果:原地摆尾版绘制实现篇用到如下主要的技术:1)、自定义Drawable动画2)、Android的坐标...

weixin_26800111的博客 465

Qt优秀开源项目之十二:shotcut

官网:https://www.shotcut.org/ github地址:https://github.com/mltframework/shotcut shotcut基于FFmpeg开发,是一款免费、开源、跨平台的视频编辑软件。因为基于FFmpeg,所以最新的音视频格式都是支持的。视频编辑只是其本质工作,居然还支持网络流媒体回放—HTTP, HLS, RTMP, RTSP, MMS, UDP 比较贴心的是官网还提供了视频教程:https://www.shotcut.org/tutorials/ 功能强大没

草上爬的博客 5314

自定义Drawable实现灵动的红鲤鱼动画(下篇)

上篇文章自定义Drawable实现灵动的红鲤鱼动画(上篇)我们绘制了可以摆动身体的小鱼,本篇就分享一下如何让小鱼游到手指点击的位置。用到的主要技术如下: 1)、三阶贝塞尔曲线 2)、Path的Measure 一、动画分析小鱼的行走不是简单的位移,不难看出在小鱼位移的同时身体的角度还随着前进的方向而变化,所以本篇要解决如下两部分: 1)、鱼身的位移 2)、鱼身的旋转

Jcs_533的博客 1185

Android 14+ 模拟器抓包实录:把 Burp CA 装成系统 CA,让 targetSdk≥34 的 App 乖乖解密

本文记录了在 Android 14+ 环境下,通过将 Burp CA 安装为系统信任锚,成功抓取 targetSdk=35 App 的 HTTPS 明文流量的完整实操过程。针对“浏览器可用、App 不可用”的典型现象,精准识别出根本原因是系统级证书信任策略变更(用户安装的 CA 被屏蔽),而非 SSL Pinning。仅通过 adb 命令将 CA 推送至系统证书存储并重启生效,无需 Frida、Objection 或修改 APK,实现零侵入解密。全文命令均基于 Windows + MuMu 模拟器环境实测通

JIANqiao19931029的博客 341
上一篇: 如何应对Android面试官-> 自定义 PhotoView 事件分发
下一篇: 如何应对Android面试官->实战高级UI,用自定义View画一条锦鲤(下)
老A说
博客等级 码龄14年 1181粉丝 85原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值