速度码住:鸿蒙OS开发徽章组件指南

652 篇文章 6 订阅
647 篇文章 7 订阅

现在很多的 APP 会有新消息/未接来电/未读消息/新通知圆球红点提示,典型的以微信、QQ 新消息提示为例。

当微信朋友圈有新的朋友更新/发布朋友圈消息后,在微信的底部切换卡上会有一个红色的小圆球红点,表示有新消息,提示用户查看。在消息通讯类的 APP 中十分实用。

功能介绍

鸿蒙 BGABadgeView 徽章组件,主要功能包括:传入图片生成徽章,设置文本生成文本徽章,并且每个徽章都具有拖拽超范围即可消除,范围内即可回到原位置。

模拟机效果图如下:

①图片徽章:

图片

图片

②文字徽章:

图片

③拖动徽章爆炸:

图片

使用时候,直接将其下载,作为一个 har 包导入到自己的项目中即可。下面则详细介绍 BGABadgeView 的使用以及开发指南。

BGABadgeView 使用指南

①新建工程, 添加组件 Har 包依赖

在应用模块中添加 HAR,只需要将 verificationcodeview-debug.har 复制到 entry\libs 目录下即可。

②修改配置文件

修改主页面的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:id="$+id:layout1"
    ohos:orientation="vertical">
    <DependentLayout
        ohos:id="$+id:dependent1"
        ohos:height="200vp"
        ohos:width="match_parent">

        <com.example.bgabadgecomp_library.BAGDragBadgeImage
            ohos:top_margin="15vp"
            ohos:right_margin="10vp"
            ohos:bottom_margin="10vp"
            ohos:height="80vp"
            ohos:width="80vp"
            ohos:scale_mode="zoom_center"
            ohos:image_src="$media:avator"
            ohos:id="$+id:image1"
            ohos:below="$id:title"
            ohos:left_margin="30vp"/>
        <Image
            ohos:top_margin="15vp"
            ohos:right_margin="10vp"
            ohos:bottom_margin="10vp"
            ohos:height="80vp"
            ohos:width="80vp"
            ohos:scale_mode="zoom_center"
            ohos:image_src="$media:avator"
            ohos:id="$+id:image2"
            ohos:end_of="$id:image1"
            ohos:below="$id:title"
            ohos:left_margin="10vp"/>
           </DependentLayout>
        <Text
            ohos:left_margin="30vp"
            ohos:id="$+id:text1"
            ohos:top_margin="10vp"
            ohos:right_margin="15vp"
            ohos:bottom_margin="10vp"
            ohos:height="40vp"
            ohos:width="match_parent"
            ohos:text="测试1"
            ohos:below="$id:dependent1"
            ohos:text_size="20vp"/>
</DependentLayout>

修改 MainAbilitySlice 中的 UI 加载代码,在 MainAbilitySlince 类的 onStart 函数中,增加如下代码:

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);

    BAGDragBadgeImage bagDragBadgeImage = (BAGDragBadgeImage) findComponentById(ResourceTable.Id_image1);
    bagDragBadgeImage.setCornerRadius(bagDragBadgeImage.getWidth() / 2); // 圆形边框
    DependentLayout stackLayout = (DependentLayout) findComponentById(ResourceTable.Id_layout1);

    Image image2 = (Image) findComponentById(ResourceTable.Id_image2);
    image2.setCornerRadius(20);

    DependentLayout.LayoutConfig config = new DependentLayout.LayoutConfig(DependentLayout.LayoutConfig.MATCH_PARENT, DependentLayout.LayoutConfig.MATCH_PARENT);

    RoundRectImage roundRectImage = RoundRectImage.attach2Window(this, stackLayout, image2, config, BGABadgeViewHelper.getPixelMap(this, ResourceTable.Media_avatar_vip));

    RoundRectText roundRectText = RoundRectText.attach2Window(this, stackLayout, image3, config);

    Text text1  = (Text) findComponentById(ResourceTable.Id_text1);
    RoundRectText roundText1 = RoundRectText.attach2Window(this, stackLayout, text1, config);
    roundText1.setBadgeText("qqqqqqqq");
    List<Component> componentList = new ArrayList<>();
    componentList.add(roundRectText);
    componentList.add(roundText1);

    stackLayout.setTouchEventListener(new Component.TouchEventListener() {
        @Override
        public boolean onTouchEvent(Component component, TouchEvent event) {

            switch (event.getAction()) {
                case TouchEvent.PRIMARY_POINT_DOWN:// 手指第一次触摸到屏幕
                    int startX = (int) event.getPointerPosition(event.getIndex()).getX();
                    int startY = (int) event.getPointerPosition(event.getIndex()).getY();
                   if (startX < roundRectImage.getCircleLeft() + 2 * roundRectImage.getCircleRadius()
                           && startX > roundRectImage.getCircleLeft()
                           && startY < roundRectImage.getCircleTop() + 2 * roundRectImage.getCircleRadius()
                           && startY > roundRectImage.getCircleTop()) {
                       roundRectImage.setDraggedListener(DRAG_HORIZONTAL_VERTICAL, roundRectImage );

                       for (Component component1 : componentList) {
                           component1.setDraggedListener(DRAG_HORIZONTAL_VERTICAL,null);
                       }
                   } else {
                       roundRectImage.setDraggedListener(DRAG_HORIZONTAL_VERTICAL, null );

                       for (Component component1 : componentList) {
                           RoundRectText rectText = (RoundRectText) component1;
                           if (startX < rectText.getCircleLeft() + 2 * rectText.getRadius()
                                   && startX > rectText.getCircleLeft()
                                   && startY < rectText.getCircleTop() + 2 * rectText.getRadius()
                                   && startY > rectText.getCircleTop()) {
                               component1.setDraggedListener(DRAG_HORIZONTAL_VERTICAL, (Component.DraggedListener) component1);
                           } else {
                               component1.setDraggedListener(DRAG_HORIZONTAL_VERTICAL,null);
                           }
                       }
                   }

                    break;
                case TouchEvent.PRIMARY_POINT_UP:
                case TouchEvent.POINT_MOVE:
                default:
                    break;
            }
            return true;
        }
    });
}

通过以上两个步骤,就实现了简单的徽章组件,接下来在一起看下徽章组件是如何实现的。

BGABadgeView 开发指南

①新建一个 Module

新建一个 Module,类型选择 HarmonyOS Library,模块名为 VerificationCodeView,如下图:

图片

②新建一个 RoundRectText 类

实现自定义 RoundRectText 绘制:

@Override
public void onDraw(Component component, Canvas canvas){
    length = mBadgeText.length();
    Paint mTextPain = new Paint();
    mTextPain.setColor(Color.WHITE);
    mTextPain.setStyle(Paint.Style.FILL_STYLE);
    mTextPain.setTextSize(30);
    mTextPain.setFont(Font.DEFAULT);
    Rect textBounds = mTextPain.getTextBounds(mBadgeText);

    Paint mBadgePaint = new Paint();
    mBadgePaint.setColor(Color.RED);
    mBadgePaint.setStyle(Paint.Style.FILL_STYLE);
    mBadgePaint.setStrokeWidth(5);
    if (mBadgeRectF == null) {
        switch (mBadgeGravity) {
            case RightTop:
                int left = mComponent.getLeft();
                int top = mComponent.getTop();
                circleLeft = mComponent.getWidth() + left - 2 * radius - 15 * (length - 2);
                circleTop = top;
                mBadgeRectF = new RectFloat( circleLeft, circleTop, circleLeft + 2 * radius + 15 * (length - 2)  , circleTop + 2 * radius);
                break;
            case RightCenter:
                left = mComponent.getLeft();
                top = mComponent.getTop();
                circleLeft = mComponent.getWidth() + left - 2 * radius - 15 * (length - 2);
                circleTop = top + (float)mComponent.getHeight() / 2 - radius;
                mBadgeRectF = new RectFloat( circleLeft, circleTop, circleLeft + 2 * radius + 15 * (length - 2) , circleTop + 2 * radius);

                break;
            case RightBottom:
                mBadgeRectF = new RectFloat();
                left = mComponent.getLeft();
                top = mComponent.getTop();
                circleLeft = mComponent.getWidth() + left - 2 * radius - 15 * (length - 2) ;
                circleTop = top + mComponent.getHeight() - 2 * radius;
                mBadgeRectF = new RectFloat( circleLeft, circleTop, circleLeft + 2 * radius + 15 * (length - 2) , circleTop + 2 * radius);

                break;
            default:
                break;
        }
    }
    path = (float) Math.sqrt((mBadgeRectF.left - circleLeft) * (mBadgeRectF.left - circleLeft) + (mBadgeRectF.top - circleTop) * (mBadgeRectF.top - circleTop));
    isOverPath = path > overPath;
    float offSet = (float) (textBounds.top + textBounds.bottom) / 2;
    float boundsX = 0 ;
    if( 15 * length < (mBadgeRectF.right - mBadgeRectF.left)){
       float temp =  mBadgeRectF.right - mBadgeRectF.left - 15 * length;
        boundsX = temp / 2;
    }
   float roundNum = 2 * radius / (mBadgeRectF.right - mBadgeRectF.left) ;
    canvas.drawRoundRect(mBadgeRectF,roundNum * radius ,roundNum * radius, mBadgePaint);
    canvas.drawText(mTextPain, mBadgeText, mBadgeRectF.left + boundsX, mBadgeRectF.top + radius - offSet);
}

生成拖拽事件:

@Override
public void onDragDown(Component component, DragInfo dragInfo) {
     pointX = dragInfo.downPoint.getPointX();
     pointY = dragInfo.downPoint.getPointY();
    if (pointX <= circleLeft || pointX >= circleLeft + 2 * radius + 15 * (length - 2)
            || pointY <= circleTop || pointY >= circleTop + 2 * radius) {
        onDragCancel(component, dragInfo);
    }
}

@Override
public void onDragStart(Component component, DragInfo dragInfo) {
}
@Override
public void onDragUpdate(Component component, DragInfo dragInfo) {

    float left = mBadgeRectF.left;
    float right = mBadgeRectF.right;
    float top = mBadgeRectF.top;
    float bottom = mBadgeRectF.bottom;

    if (pointX <= circleLeft || pointX >= circleLeft + 2 * radius + 15 * (length - 2)
            || pointY <= circleTop || pointY >= circleTop + 2 * radius) {
        onDragCancel(component, dragInfo);
    } else {
        mBadgeRectF.left = (float) (left + dragInfo.xOffset);
        mBadgeRectF.right = (float) (right + dragInfo.xOffset);
        mBadgeRectF.top = (float) (top + dragInfo.yOffset);
        mBadgeRectF.bottom = (float) (bottom + dragInfo.yOffset);
        invalidate();
    }

}
@Override
public void onDragEnd(Component component, DragInfo dragInfo) {
    if (isOverPath) {
        explosionField.explode(component, mBadgeRectF, explosionFieldColor);
    } else {
        mBadgeRectF = new RectFloat(circleLeft, circleTop , circleLeft + 2 * radius + 15 * (length - 2), circleTop + 2 * radius);
        invalidate();
    }
}
@Override
public void onDragCancel(Component component, DragInfo dragInfo) {
    mBadgeRectF = new RectFloat(circleLeft, circleTop , circleLeft + 2 * radius + 15 * (length - 2), circleTop + 2 * radius);
    invalidate();
}

具体代码请下载项目查看。

③编译 HAR 包

利用 Gradle 可以将 HarmonyOS Library 库模块构建为 HAR 包。

构建 HAR 包的方法如下:

  • 在 Gradle 构建任务中,双击 PackageDebugHar 或 PackageReleaseHar 任务,构建 Debug 类型或 Release 类型的 HAR。

  • 待构建任务完成后,可以在工程目录中的 VerificationCodeView→bulid→outputs→har 目录中,获取生成的 HAR 包。

图片

最后

如果你想成为一名鸿蒙开发者,以下这些资料将是十分优质且有价值,让你的鸿蒙开发之路事半功倍!相对于网上那些碎片化的知识内容,这份学习资料的知识点更加系统化,更容易理解和记忆。

内容包含了:【OpenHarmony多媒体技术、Stage模型、ArkUI多端部署、分布式应用开发、音频、视频、WebGL、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战】等技术知识点。

鸿蒙Next全套VIP学习资料←点击领取!(安全链接,放心点击

1.鸿蒙核心技术学习路线

2.大厂面试必问面试题

3.鸿蒙南向开发技术

 4.鸿蒙APP开发必备

 5.HarmonyOS Next 最新全套视频教程

 6.鸿蒙生态应用开发白皮书V2.0PDF

这份全套完整版的学习资料已经全部打包好,朋友们如果需要可以点击鸿蒙Next全套VIP学习资料:免费领取(安全链接,放心点击

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值