HarmonyOS 鸿蒙Next 有没有多阶贝赛尔曲线实现案例?

发布于 1周前 作者 htzhanglong 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 有没有多阶贝赛尔曲线实现案例? 有没有多阶贝赛尔曲线实现案例?目前看到函数只是最多三阶

![无图片]

2 回复

提供drawing接口实现的多阶贝赛尔曲线demo

import { DrawContext, FrameNode, NodeController, RenderNode } from '@ohos.arkui.node';
import { UIContext } from '@ohos.arkui.UIContext';
import drawing from '@ohos.graphics.drawing';
import display from '@ohos.display';
import image from '@ohos.multimedia.image';

const TAG = 'DrawingTSSample';
let screen = display.getDefaultDisplaySync();
let screenWidth = screen.width;
let screenHeight = screen.height;
let pixelMap_: image.PixelMap | undefined;

class MyRenderNode extends RenderNode {
    private getPixmapFromMedia(resource: Resource): PixelMap {
        const unit8Array = getContext(this)?.resourceManager?.getMediaContentSync({
            bundleName: resource.bundleName,
            moduleName: resource.moduleName,
            id: resource.id
        });
        const imageSource = image.createImageSource(unit8Array.buffer.slice(0, unit8Array.buffer.byteLength));
        const createPixelMap: image.PixelMap = imageSource.createPixelMapSync({
            desiredPixelFormat: image.PixelMapFormat.RGBA_8888
        });
        createPixelMap.scaleSync(1, 1);
        return createPixelMap;
    }

    private getPath(startX: number, startY: number): drawing.Path {
        //滑块高度
        const blockHeight: number = vp2px(50);
        //滑块凸起部分高度
        const bulgingHeight: number = vp2px(10);
        //四个角圆弧半径
        const arcHeight: number = vp2px(5);
        //上下左右半圆半径大小
        const circleRadius: number = vp2px(6.5);
        //凸起半圆距边缘的间距
        const circleSpacing: number = vp2px(3.5);
        //上下左右半圆半径大小
        const edgeHeight: number = vp2px(13.5);
        //上下左右半圆贝塞尔曲线系数
        const circleBezierRatio: number = 0.5523;

        const path = new drawing.Path();
        path.moveTo(startX, startY + bulgingHeight + edgeHeight);
        path.lineTo(startX, startY + bulgingHeight + arcHeight);
        //左上角圆弧
        path.quadTo(startX, startY + bulgingHeight, startX + arcHeight, startY + bulgingHeight);
        path.lineTo(startX + edgeHeight, startY + bulgingHeight);
        //顶部半圆
        path.arcTo(startX + edgeHeight, startY, startX + edgeHeight + circleRadius * 2, startY + circleRadius * 2, 180, 180);
        path.lineTo(startX + edgeHeight + circleRadius * 2, startY + bulgingHeight);
        //右上角圆弧
        path.arcTo(startX + blockHeight - bulgingHeight * 2, startY + bulgingHeight, startX + blockHeight - bulgingHeight, startY + bulgingHeight * 2, 270, 90);
        path.lineTo(startX + blockHeight - bulgingHeight, startY + bulgingHeight + edgeHeight);
        //右侧半圆
        path.arcTo(startX + blockHeight - circleRadius * 2, startY + bulgingHeight + edgeHeight, startX + blockHeight, startY + bulgingHeight + edgeHeight + circleRadius * 2, 270, 180);
        path.lineTo(startX + blockHeight - bulgingHeight, startY + bulgingHeight + edgeHeight + circleRadius * 2);
        //右下角圆弧
        path.arcTo(startX + blockHeight - bulgingHeight * 2, startY + blockHeight - bulgingHeight, startX + blockHeight - bulgingHeight, startY + blockHeight, 0, 90);
        path.lineTo(startX + blockHeight - bulgingHeight - edgeHeight, startY + blockHeight);
        //底部半圆
        path.lineTo(startX + blockHeight - bulgingHeight - edgeHeight, startY + blockHeight - circleSpacing);
        //底部半圆中心点坐标
        const bottomCenterX = startX + bulgingHeight * 2;
        const bottomCenterY = startY + blockHeight - circleSpacing;
        //底部半圆右侧1/4圆弧
        path.cubicTo(bottomCenterX + circleRadius, bottomCenterY - circleRadius * circleBezierRatio, bottomCenterX + circleRadius * circleBezierRatio, bottomCenterY - circleRadius, bottomCenterX, bottomCenterY - circleRadius);
        //底部半圆左侧1/4圆弧
        path.cubicTo(bottomCenterX - circleRadius * circleBezierRatio, bottomCenterY - circleRadius, bottomCenterX - circleRadius, bottomCenterY - circleRadius * circleBezierRatio, bottomCenterX - circleRadius, bottomCenterY);

        path.lineTo(startX + edgeHeight, startY + blockHeight);

        //左下角圆弧
        path.arcTo(startX, startY + blockHeight - bulgingHeight, startX + bulgingHeight, startY + blockHeight, 90, 90);
        path.lineTo(startX, startY + blockHeight - edgeHeight);
        //左侧半圆
        //左侧半圆中心点坐标
        path.lineTo(startX + circleSpacing, startY + blockHeight - edgeHeight);
        const leftCenterX = startX + circleSpacing;
        const leftCenterY = startY + edgeHeight + bulgingHeight + circleRadius;
        //左侧半圆右侧1/4圆弧
        path.cubicTo(leftCenterX + circleRadius * circleBezierRatio, leftCenterY + circleRadius, leftCenterX + circleRadius, leftCenterY + circleRadius * circleBezierRatio, leftCenterX + circleRadius, leftCenterY);
        //左侧半圆左侧1/4圆弧
        path.cubicTo(leftCenterX + circleRadius, leftCenterY - circleRadius * circleBezierRatio, leftCenterX + circleRadius * circleBezierRatio, leftCenterY - circleRadius, leftCenterX, leftCenterY - circleRadius);

        path.lineTo(startX, startY + edgeHeight + bulgingHeight);
        return path;
    }

    // 在RenderNode的draw中使用drawing自定义绘制
    async draw(context: DrawContext) {
        const canvas = context.canvas;
        let pixelMap: image.PixelMap = this.getPixmapFromMedia($r('app.media.icon_yummy_half_block_pic_02'));
        canvas.clipPath(this.getPath(600, 100), drawing.ClipOp.INTERSECT, true);
        let options = new drawing.SamplingOptions(drawing.FilterMode.FILTER_MODE_NEAREST);
        if (pixelMap != null) {
            canvas.drawImage(pixelMap, 0, 0, options);
        }
    }
}

// 创建一个MyRenderNode对象
const newNode = new MyRenderNode();
// 定义newNode的像素格式
newNode.frame = {
    x: 0,
    y: 0,
    width: screenWidth,
    height: screenHeight
};

class TextRenderNode extends RenderNode {
    async draw(context: DrawContext) {
        const canvas = context.canvas;
        let brush = new drawing.Brush();
        brush.setColor({
            alpha: 255,
            red: 255,
            green: 0,
            blue: 0
        });
        let font = new drawing.Font();
        font.setSize(50);
        const textBlob = drawing.TextBlob.makeFromString("Hello World", font, drawing.TextEncoding.TEXT_ENCODING_UTF8);
        canvas.attachBrush(brush);
        canvas.drawTextBlob(textBlob, 60, screenHeight / 4);
        canvas.detachBrush();
    }
}

// 创建一个TextRenderNode对象
const textNode = new TextRenderNode();
// 定义textNode的像素格式
textNode.frame = {
    x: 0,
    y: 0,
    width: screenWidth,
    height: screenHeight
};

class MyNodeController extends NodeController {
    private rootNode: FrameNode | null = null;

    makeNode(uiContext: UIContext): FrameNode {
        this.rootNode = new FrameNode(uiContext);
        if (this.rootNode === null) {
            return this.rootNode;
        }
        const renderNode = this.rootNode.getRenderNode();
        if (renderNode !== null) {
            renderNode.frame = {
                x: 0,
                y: 0,
                width: 10,
                height: 500
            };
            renderNode.pivot = { x: 50, y: 50 };
        }
        return this.rootNode;
    }

    addNode(node: RenderNode): void {
        if (this.rootNode === null) {
            return;
        }
        const renderNode = this.rootNode.getRenderNode();
        if (renderNode !== null) {
            renderNode.appendChild(node);
        }
    }

    clearNodes(): void {
        if (this.rootNode === null) {
            return;
        }
        const renderNode = this.rootNode.getRenderNode();
        if (renderNode !== null) {
            renderNode.clearChildren();
        }
    }
}

@Entry
@Component
struct RenderTest {
    private settings: RenderingContextSettings = new RenderingContextSettings(true);
    private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
    private myNodeController: MyNodeController = new MyNodeController();

    build() {
        Column() {
            Row() {
                NodeContainer(this.myNodeController)
                    .height('100%')
                Button("Draw Path")
                    .margin({ bottom: 20, right: 12 })
                    .onClick(() => {
                        this.myNodeController.clearNodes();
                        this.myNodeController.addNode(newNode);
                    })
            }
            .width('100%')
            .justifyContent(FlexAlign.Center)
            .shadow(ShadowStyle.OUTER_DEFAULT_SM)
            .alignItems(VerticalAlign.Bottom)
            .layoutWeight(1)
        }
    }

    // 将离屏绘制好的bitmap绘制到屏幕上
    public async drawImage() {
        if (pixelMap_ === null) {
            console.error(TAG, 'draw image pixelMap_ is null');
            return;
        }
        console.log(TAG, 'drawImage success');
        this.context.drawImage(pixelMap_, 0, 100);
    }
}

三方库链接:https://gitee.com/openharmony-tpc/ohos_mpchart#mpchart

请看下是否有效

更多关于HarmonyOS 鸿蒙Next 有没有多阶贝赛尔曲线实现案例?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


针对帖子标题“HarmonyOS 鸿蒙Next 有没有多阶贝赛尔曲线实现案例?”的问题,以下是专业且简洁的回答:

HarmonyOS 鸿蒙Next系统中,确实支持多阶贝赛尔曲线的实现。贝赛尔曲线作为一种重要的数学工具,在图形绘制、动画效果等领域有着广泛应用。在鸿蒙系统的开发框架中,你可以通过其提供的图形绘制API来实现多阶贝赛尔曲线。

具体来说,鸿蒙系统提供了丰富的图形绘制接口,这些接口支持绘制各种复杂的图形,包括多阶贝赛尔曲线。开发者可以利用这些接口,根据贝赛尔曲线的数学定义,传入相应的控制点坐标,从而绘制出所需的多阶贝赛尔曲线。

不过,需要注意的是,鸿蒙系统的API可能会随着版本的更新而有所变化,因此建议查阅最新的鸿蒙系统开发者文档,以获取最准确的信息和示例代码。

如果你正在寻找具体的实现案例,可以尝试在鸿蒙系统的开发者社区或者相关论坛中搜索,通常会有其他开发者分享他们的实现经验和代码片段。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部