【cocos creator】ScrollView + RichText实现可滑动的富文本显示自定义组件

ScrollView + RichText实现可滑动的富文本显示自定义组件

通过将ScrollView滑动视图组件和RichText富文本组件组合,同时实现文字自动滑动的效果。

为适应和实现多种不同的显示效果,我设计组件的节点树为

ContentDisplay
├──Background
├──Foreground
│     ├──TextContent

ContentDisPlay节点作为整个组件的根节点,并挂载脚本实现组件的功能。

Background节点作为整个组件的背景节点,可为富文本显示添加背景,例如背景图,或做成遮罩层。

Foreground表示整个富文本显示的区域。其中TextContent同时挂载了RichText和ScrollView组件。
节点树
预览图
上图中蓝色框为Background,灰色框为Foreground。
TextContent挂载RichText和ScrollView组件
接下来是重点,通过脚本控制RichText的滑动。我将脚本分为三个文件,分别挂载到ContentDisplay根节点和Background,Foreground节点上。

此处主要实现了前景的富文本滑动,实际上Background未包含脚本。计划后面再加上对背景的个性控制。这里只写了ContentDisplay和Foreground脚本。

ContentDisplay 脚本,两个子节点作为成员变量。在其他地方通过此对象的此成员变量引用和调用。

//ContentDisplay 脚本,两个子节点作为成员变量。在其他地方通过此对象的此成员变量引用和调用。
//import
import foreground from "./foreground"
import background from "./background"

const {ccclass, property} = cc._decorator;
/**
 * contextDisplay is a custom component to show some rich text.
 * It's include a background view layer and foreground view layer.
 * the background layer to do some thing like mask work
 * the foreground layer is for show rich text
 */
@ccclass
export default class contentDisplay extends cc.Component {

    public background: background;
    public foreground: foreground;

    onLoad () {
        console.log("----onLoad contentDisplay----");
        
        this.background = this.node.getChildByName("Background").getComponent(background);
        this.foreground = this.node.getChildByName("Foreground").getComponent(foreground);

    }

}

Foreground脚本,提供对文本内容,区域大小,是否自动滑动,是否自动返回顶部的设置接口。

//Foreground脚本,提供对文本内容,区域大小,是否自动滑动,是否自动返回顶部的设置接口。
const {ccclass, property} = cc._decorator;

@ccclass
export default class foreground extends cc.Component {

    //子节点,该节点挂载了富文本和滑动组件
    private textContentNode: cc.Node;
    //富文本组件
    private richText: cc.RichText;
    //滑动组件
    private scroll: cc.ScrollView;

    //当前状态是否可以自动滑动。
    private canSlider: boolean = false;

    //属性,设置当滑动到底部之后是否自动返回顶部
    @property(Boolean)
    public autoToTop: boolean = true;
    //属性,设置是否自动滑动
    @property(Boolean)
    private autoSlider: boolean = false;
    //属性,设置滑动的时间间隔。
    @property(Number)
    private sliderInterval: number = 0.01
    //属性,设置滑动每次时间间隔滑动的距离。
    @property(Number)
    private sliderSpeed: number = 50;

    onLoad () {
        console.log("----onLoad foreground----");
        this.textContentNode = this.node.getChildByName("TextContent");

        this.richText = this.textContentNode.getComponent(cc.RichText);
        this.scroll = this.textContentNode.getComponent(cc.ScrollView);
    }

    start(){
        //初始化后,判断属性,是否需要自动滑动
        if(this.autoSlider){
            this.addAutoSlider();
        }
        //由于官方自带组件ScrollView的问题,当取消滚动惯性之后,scroll-to-bottom事件不会被触发,此处需要自己监听是否滑动到底部。并判断是否需要返回顶部。
        this.scroll.node.on("scroll-to-bottom", function ( event ) {
            console.log(this.autoToTop);
            if(this.autoToTop){
                this.scroll.content.setPosition(0, 0);
            }
          }.bind(this));
    }
    
    //设置文本区的宽高
    setTextContentNode(height: number, width: number){
        this.textContentNode.height = height;
        this.textContentNode.width = width;
        this.richText.maxWidth = width;
    }
    
    //设置富文本内容
    setContent(string: string){
        this.richText.string = string;
    }

    //设置富文本显示位置
    setContentPosition(position: cc.Vec2){
        this.scroll.content.setPosition(position);
    }

    //获取富文本当前显示的位置
    getContentPosition(): cc.Vec2{
        return this.scroll.content.getPosition();
    }

    //获取富文本内容
    getContent(): string{
        return this.richText.string;
    }

    //通过计时器设置自动滑动
    addAutoSlider(){
        this.autoSlider = true;
        this.scroll.content.setPosition(0, 0);
        if(this.autoSlider){
            this.schedule(this.autoSliderCallback.bind(this),this.sliderInterval);
        }
    }

    //自动滑动计时器的callback
    autoSliderCallback(){
        //Judging whether or not to slider
        if(this.scroll.content.getPosition().y >= this.scroll.content.height - this.node.height * 0.5){
            this.canSlider = false;
            this.scroll.node.emit("scroll-to-bottom");
        }else{
            this.canSlider = true;
        }
        if(!this.canSlider){
            return;
        }
        let x: number = this.scroll.content.getPosition().x;
        let y:number = this.scroll.content.getPosition().y + this.sliderSpeed * this.sliderInterval;
        this.scroll.content.setPosition(x, y);
    }

    //取消自动滑动
    cancelAutoSlider(){
        this.unschedule(this.autoSliderCallback);
        this.autoSlider = false;
    }

}

测试脚本

import contentDisplay from "../contentDisplay/contentDisplay"

const {ccclass, property} = cc._decorator;

@ccclass
export default class gameTest extends cc.Component {

    cd: contentDisplay = null;
    endPoem: string = "";

    onLoad () {
        console.log("----onLoad contentDisplay----");
        this.cd = cc.find("Canvas/ContentDisplay").getComponent(contentDisplay);
        console.log(this.cd);

        
    }

    start () {
        this.cd.foreground.setTextContentNode(480, 640);
        cc.loader.loadRes('data/endPoem.json', function(err,res){
            if (err) {
                cc.log(err);
            }else{
                let list=res;
                this.cd.foreground.setContent(list.json.endPoem);
                this.cd.foreground.addAutoSlider();
            }
        }.bind(this));
    }
}

此处使用了Minecraft的<< End Poem >>来做测试。
最终显示效果
测试图
完成组建之后,拖拽到资源目录成为预制体,就可以到处使用了。

这是第一次尝试制作cocos cretor自定义组件,还有很多不足的地方,欢迎大家批评指点。

cocos creator~为节点通过代码动态添加自定义组件

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值