cocos2dx 3.17.2 lua RichText使用
做聊天时需使用富文本功能实现不同颜色文本,下划线,根据固定宽度自动换行,点击部分文本触发一些事件等由此想到了引擎自带的richtext
之前的版本也用过richtext由于诸多问题以及功能不多选择的都是网上用node或者label实现的富文本,这个版本查看了api文档后发现大部分功能以及实现了,那就不需要自己造轮子了
但是实际使用时发现诸多问题,特此记录一下,做备忘也给其他需要的朋友参考
1.ccui.RichText可以根据xml格式初始化,实现了大部分我需要的功能,格式放在下面,或者直接去我参考的作者链接https://blog.csdn.net/qq_26701531/article/details/81634336
<font face='xxx.ttf' size='24' color='#0000ff'>text</font> <small>text</small> <big>text</big> <u>text</u> 下划线/ <i>text</i> 斜体字/ <b>text</b> 加粗/ <del>text</del> 中划线/ <img src='cocosui/sliderballnormal.png' width='30' height='30'/> 图片 / <a href='http://www.google.com'>click me text </a> 链接 / <br/> 换行 == /n / <outline color=\"#D2B48C\" size=\"2\">text</outline> 描边/ <shadow color=\"#4169E1\" offsetWidth=\"8\" offsetHeight=\"-8\" blurRadius=\"2\">text</shadow> 阴影/ <glow color=\"#AFEEEE\">text</glow> 外发光/
2.RichText:createWithXML (xml,defaults,handleOpenUrl)使用时发现三个参数,第一个传xml的字符串(上文提到的那些),第二个是默认的富文本格式,第三个为打开url的回调,
由于lua这边没有太多信息,去翻看c++源码发现,除了第一个参数必传之外,另外两个参数都是有默认值的,
(1)lua这边提示必须传2个以上参数,修改lua_cocos2dx_ui_auto.cpp文件里面对应的函数参数,增加只传一个参数的选项
(2)使用时发现不管第三个参数如何传都会被断言卡住,查看lua_cocos2dx_ui_auto.cpp时发现如下代码
do { // Lambda binding for lua is not supported. assert(false); } while(0) ;
提示 Lambda binding for lua is not supported.然后就没绑定,修改之后增加绑定
修改以上两点后的代码如下(去lua_cocos2dx_ui_auto.cpp里面搜索lua_cocos2dx_ui_RichText_createWithXML,红色部分为我增加和修改)
int lua_cocos2dx_ui_RichText_createWithXML(lua_State* tolua_S) { int argc = 0; bool ok = true; #if COCOS2D_DEBUG >= 1 tolua_Error tolua_err; #endif #if COCOS2D_DEBUG >= 1 if (!tolua_isusertable(tolua_S,1,"ccui.RichText",0,&tolua_err)) goto tolua_lerror; #endif argc = lua_gettop(tolua_S) - 1; if (argc == 1) { std::string arg0; ok &= luaval_to_std_string(tolua_S, 2,&arg0, "ccui.RichText:createWithXML"); if(!ok) { tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_ui_RichText_createWithXML'", nullptr); return 0; } cocos2d::ui::RichText* ret = cocos2d::ui::RichText::createWithXML(arg0); object_to_luaval<cocos2d::ui::RichText>(tolua_S, "ccui.RichText",(cocos2d::ui::RichText*)ret); return 1; } if (argc == 2) { std::string arg0; cocos2d::ValueMap arg1; ok &= luaval_to_std_string(tolua_S, 2,&arg0, "ccui.RichText:createWithXML"); ok &= luaval_to_ccvaluemap(tolua_S, 3, &arg1, "ccui.RichText:createWithXML"); if(!ok) { tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_ui_RichText_createWithXML'", nullptr); return 0; } cocos2d::ui::RichText* ret = cocos2d::ui::RichText::createWithXML(arg0, arg1); object_to_luaval<cocos2d::ui::RichText>(tolua_S, "ccui.RichText",(cocos2d::ui::RichText*)ret); return 1; } if (argc == 3) { std::string arg0; cocos2d::ValueMap arg1; std::function<void (const std::string&)> arg2; ok &= luaval_to_std_string(tolua_S, 2,&arg0, "ccui.RichText:createWithXML"); ok &= luaval_to_ccvaluemap(tolua_S, 3, &arg1, "ccui.RichText:createWithXML"); // do { // // Lambda binding for lua is not supported. // assert(false); // } while(0) // ; #if COCOS2D_DEBUG >= 1 if (!toluafix_isfunction(tolua_S,4,"LUA_FUNCTION",0,&tolua_err) ) { goto tolua_lerror; } #endif LUA_FUNCTION handler = toluafix_ref_function(tolua_S,4,0); arg2 = [handler](std::string str) { LuaStack* stack = LuaEngine::getInstance()->getLuaStack(); stack->pushString(str.c_str()); stack->executeFunctionByHandler(handler, 1); }; if(!ok) { tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_ui_RichText_createWithXML'", nullptr); return 0; } cocos2d::ui::RichText* ret = cocos2d::ui::RichText::createWithXML(arg0, arg1, arg2); object_to_luaval<cocos2d::ui::RichText>(tolua_S, "ccui.RichText",(cocos2d::ui::RichText*)ret); return 1; } luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "ccui.RichText:createWithXML",argc, 1); return 0; #if COCOS2D_DEBUG >= 1 tolua_lerror: tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_ui_RichText_createWithXML'.",&tolua_err); #endif return 0; }
3.使用handleOpenUrl回调时发现一个问题,在空白场景时好用,去了我的弹窗界面等就不好用了,经过排查后发现是因为UIRichText.cpp里面触发handleOpenUrl的触摸为多点触摸,但是底层的机制为单点触摸优先多点,实际使用时各种ui界面肯定会吞噬触摸,防止界面点穿,这就导致,还没触发多点触摸已经被吞噬了,后来没有办法只能修改handleOpenUrl触发为单点触摸,不知道引擎为啥会给它使用多点触摸,
修改方法打开UIRichText.cpp搜索EventListenerTouchAllAtOnce(里面就只有一个,或者搜索ListenerComponent),将该多点触摸改成单点EventListenerTouchOneByOne,其他的代码就是注册相应的监听了,我就不贴出来了,有一点需要注意,因为单点的默认优先级都为0,我们使用富文本时一般都是最后添加的,所以优先级好像也不高,我就手动给他设置优先级为-1(越小优先级越高)addEventListenerWithSceneGraphPriority改为addEventListenerWithFixedPriority,onTouchesEnded改为onTouchEnded然后在修改下参数已经实现就好,编译完之后发现好用了
实际使用时我是通过handleOpenUrl传回来的字符串(richtext初始化时传入的url)进行判断,然后实现不同的逻辑跳转等(懒人做法),如果有需要可以自己增加参数
4.使用时会发现富文本的高度和大小获取的不对,其实时使用方式不对,贴个示例记录下
local testStr = "<font face='res/font/bmjy.ttf' size='30' color='#000000'><a href='username|用户名' ><i><u>用户名</u></i></a><img src='HelloWorld.png' width='40' height='70'/>升星成功,获得8星英雄<a href='heroname|测试' >测试</a>令人羡慕</font>" local callback = function (str) print(str) local strTab = string.split(str, "|") if strTab[1] == "username" then showToast("我是" .. strTab[2]) elseif strTab[1] == "heroname" then showToast("我是" .. strTab[2]) elseif strTab[1] == "goodsname" then showToast("我是" .. strTab[2]) end end local def = { KEY_VERTICAL_SPACE, KEY_WRAP_MODE, KEY_HORIZONTAL_ALIGNMENT, KEY_FONT_COLOR_STRING, KEY_FONT_SIZE, KEY_FONT_FACE, KEY_ANCHOR_FONT_COLOR_STRING, KEY_ANCHOR_TEXT_BOLD, KEY_ANCHOR_TEXT_ITALIC, KEY_ANCHOR_TEXT_LINE, KEY_ANCHOR_TEXT_STYLE, KEY_ANCHOR_TEXT_OUTLINE_COLOR, KEY_ANCHOR_TEXT_OUTLINE_SIZE, KEY_ANCHOR_TEXT_SHADOW_COLOR, KEY_ANCHOR_TEXT_SHADOW_OFFSET_WIDTH, KEY_ANCHOR_TEXT_SHADOW_OFFSET_HEIGHT, KEY_ANCHOR_TEXT_SHADOW_BLUR_RADIUS, KEY_ANCHOR_TEXT_GLOW_COLOR, } local test_label = ccui.RichText:createWithXML(testStr,def,callback) local ElementText_Type = { ITALICS_FLAG = 1, --/*!< italic text */ BOLD_FLAG = 2, --/*!< bold text */ UNDERLINE_FLAG= 4, -- /*!< underline */ STRIKETHROUGH_FLAG= 8, --/*!< strikethrough */ URL_FLAG= 16, -- /*!< url of anchor */ OUTLINE_FLAG= 32, -- /*!< outline effect */ SHADOW_FLAG= 64, --/*!< shadow effect */ GLOW_FLAG= 128 -- /*!< glow effect */ } local flags = 0; flags = bit._or(flags,ElementText_Type.UNDERLINE_FLAG) flags = bit._or(flags,ElementText_Type.URL_FLAG) local element = ccui.RichElementText:create(1,cc.RED,255,"抽奖券",'res/font/bmjy.ttf',30,flags,"goodsname|抽奖券") test_label:pushBackElement(element)
local width = 500 --test_label:formatText(); --该行代码之后获取大小才准 --local size = test_label:getContentSize() --local height = math.ceil(size.width / width) * size.height --test_label:ignoreContentAdaptWithSize(false) --test_label:setContentSize(width,height)
createSprite(self.layout_buttom,"common_txt_bg11.png",UI_TEX_TYPE_PLIST,width,height,cc.p(360,200)) test_label:setPosition(cc.p(360,200)) test_label:addTo(self.layout_buttom)
5.后续发现下划线颜色问题,一直显示白色,是由于label的下划线颜色_displayedColor替换了之前_textColor,不随字的颜色走了,但是富文本这边设置颜色只是设置了setTextColor字的颜色,导致下划线颜色一直默认白色,也没有参数能获取富文本内部的label,以及设置下划线颜色,我为了快,就把c++里面setTextColor换成了setColor这样就修改了_displayedColor,字和下划线颜色一样了(懒人做法,我的需求是够用了),如有需要最好是自己增加个标签或者函数来传参修改颜色
至此基本功能算是都好用了,我就去撸代码了,后续有其他的功能其实可以通过RichElementCustomNode实现,像图片以及发光,描边这些参数里带着的就不说了,有点啰嗦了
浙公网安备 33010602011771号