原文:《為cocos2d-x實現(xiàn)安卓輸入框舍咖。非全屏矩父,無dialog,綁定到lua》
http://www.cnblogs.com/wolfred7464/p/4819377.html
https://www.bbsmax.com/A/Ae5R7nmmdQ/
cocos2d-x官方自帶的輸入框排霉,簡直慘不忍睹窍株,在ios還好,在安卓簡直了攻柠。球订。用過的都知道。辙诞。辙售。
所以為了用戶體驗,我們自己搞一個吧飞涂。輸入框這種東西比較特殊旦部,不像按鈕祈搜、列表框之類的很容易實現(xiàn),因為涉及到復(fù)制粘貼士八、操作虛擬鍵盤等容燕,所以當(dāng)然是用安卓原生的輸入框最好了。
非常感謝我們的主程陳劍大哥婚度,思路是陳劍大哥想的蘸秘,我只負責(zé)記錄一下。
本來代碼50天前就寫好了蝗茁,但是綁定到j(luò)s一直失敗醋虏,惡心了好幾天放棄了。前幾天在用lua寫點東西哮翘,把之前的代碼拷過來試著綁定到lua颈嚼,結(jié)果一次就成功了,完全沒有踩坑饭寺,不知道說什么好了阻课。。而且前幾天官方發(fā)布了cocos2d-x 3.8版本艰匙,已經(jīng)自帶了限煞,所以現(xiàn)在再發(fā)出來感覺毫無競爭力了呢。员凝。署驻。
使用原生控件的優(yōu)點不用多說了,缺點當(dāng)然也是有的健霹。例如排版硕舆、布局、屏幕適配等骤公,都要適應(yīng)cocos2d的規(guī)則抚官,而且由于是系統(tǒng)控件,渲染層級不受cocos2d的zorder的影響阶捆。當(dāng)然這些努力一下也是可以解決的凌节。
要注意的有:
1、c++通過jni控制java創(chuàng)建安卓控件洒试。
2倍奢、c++持有java對象的引用,防止垃圾回收垒棋。
3卒煞、java回調(diào)c語言,c語言調(diào)用c++叼架,所以需要處理好java對象與c++對象的對應(yīng)關(guān)系畔裕。
我的做法是:
1衣撬、創(chuàng)建一個輸入框工廠類,負責(zé)根據(jù)不同平臺生成輸入框扮饶,當(dāng)然我只會安卓的具练。
2、工廠類維護一個map甜无,保存c++對象和java對象的對應(yīng)關(guān)系扛点。
3、根據(jù)cocos2d的世界坐標(biāo)系岂丘,更新安卓原生控件陵究。
防止惡意轉(zhuǎn)載還改名的惡心行為。本博客地址:http://www.cnblogs.com/wolfred7464/
上代碼吧:
EditText.h
#ifndef __CocosAndroidStudio__EditText__
#define __CocosAndroidStudio__EditText__
#include <string>
#include "cocos2d.h"
class EditText : public cocos2d::Node {
public:
virtual ~EditText() {};
;
;
protected:
};
#endif /* defined(__CocosAndroidStudio__EditText__) */
EditTextAndroid.h
#ifndef __CocosAndroidStudio__EditTextAndroid__
#define __CocosAndroidStudio__EditTextAndroid__
#include "EditText.h"
#include "platform/android/jni/JniHelper.h"
#include "EditTextFactory.h"
class EditTextAndroid : public EditText {
public:
~EditTextAndroid();
virtual void setString(const std::string& str) override;
virtual std::string getString() override;
virtual void setPosition(const cocos2d::Vec2& pos) override;
virtual void setContentSize(const cocos2d::Size& size) override;
virtual void onEnter() override;
friend class EditTextFactory;
private:
EditTextAndroid();
static EditTextAndroid* create();
cocos2d::JniMethodInfo getJavaMethod(const char* name, const char* param);
void setPositionAndroid();
void setContentSizeAndroid();
jobject _object;
};
#endif /* defined(__CocosAndroidStudio__EditTextAndroid__) */
EditTextAndroid.cpp
#include "EditTextAndroid.h"
#include "cocos2d.h"
#include <unistd.h>
#include <string>
USING_NS_CC;
using namespace std;
EditTextAndroid* EditTextAndroid::create() {
auto ret = new EditTextAndroid();
ret->autorelease();
return ret;
}
EditTextAndroid::EditTextAndroid() {
auto env = cocos2d::JniHelper::getEnv();
jclass cls = env->FindClass("org/red/tools/RedEditText");
assert(cls != NULL);
jmethodID ctor = env->GetMethodID(cls, "<init>", "()V");
assert(ctor != NULL);
this->_object = env->NewObject(cls, ctor);
env->NewGlobalRef(this->_object);
}
EditTextAndroid::~EditTextAndroid() {
auto env = cocos2d::JniHelper::getEnv();
env->DeleteGlobalRef(this->_object);
}
JniMethodInfo EditTextAndroid::getJavaMethod(const char* name, const char* param) {
JniMethodInfo info;
bool isHave = JniHelper::getMethodInfo(info, "org/red/tools/RedEditText", name, param);
assert(isHave);
return info;
}
void EditTextAndroid::setString(const std::string& str) {
auto info = getJavaMethod("setString", "(Ljava/lang/String;)V");
jstring jstr = info.env->NewStringUTF(str.c_str());
info.env->CallVoidMethod(this->_object, info.methodID, jstr);
}
std::string EditTextAndroid::getString() {
auto info = getJavaMethod("getString", "()Ljava/lang/String;");
auto jstr = (jstring)info.env->CallObjectMethod(this->_object, info.methodID);
jboolean isCopy;
auto chars = info.env->GetStringUTFChars(jstr, &isCopy);
std::string str(chars);
if(isCopy == JNI_TRUE) {
info.env->ReleaseStringUTFChars(jstr, chars);
}
info.env->DeleteLocalRef(jstr);
return str;
}
void EditTextAndroid::setPosition(const Vec2& pos) {
EditText::setPosition(pos);
setPositionAndroid();
}
void EditTextAndroid::setContentSize(const Size& size) {
EditText::setContentSize(size);
setContentSizeAndroid();
}
void EditTextAndroid::setPositionAndroid() {
if(isRunning()) {
auto pos = convertToWorldSpace(Vec2(, getContentSize().height));
auto info = getJavaMethod("setPosition", "(II)V");
auto visHeight = Director::getInstance()->getVisibleSize().height;
info.env->CallVoidMethod(this->_object, info.methodID, jint(pos.x), jint(visHeight - pos.y));
}
}
void EditTextAndroid::setContentSizeAndroid() {
if(isRunning()) {
auto realSize = SizeApplyAffineTransform(getContentSize(), getNodeToWorldAffineTransform());
auto info = getJavaMethod("setContentSize", "(II)V");
info.env->CallVoidMethod(this->_object, info.methodID, jint(realSize.width), jint(realSize.height));
}
}
void EditTextAndroid::onEnter() {
EditText::onEnter();
setPositionAndroid();
setContentSizeAndroid();
}
extern "C" {
JNIEXPORT void JNICALL Java_org_red_tools_RedEditText_nativeOnTextChanged(JNIEnv *env, jobject javaThis, jstring jstr) {
jboolean isCopy;
auto chars = env->GetStringUTFChars(jstr, &isCopy);
std::string str(chars);
if(isCopy == JNI_TRUE) {
env->ReleaseStringUTFChars(jstr, chars);
}
log("[Red] textChanged: %s", str.c_str());
}
}
EditTextFactory.h
#ifndef __CocosAndroidStudio__EditTextFactory__
#define __CocosAndroidStudio__EditTextFactory__
#include "EditText.h"
#include <map>
#include "platform/android/jni/JniHelper.h"
class EditTextFactory {
public:
static EditTextFactory* getInstance();
EditText* createEditText();
EditText* getEditTextByJobject(jobject obj);
private:
EditTextFactory();
std::map<jobject, EditText*> _map;
};
#endif /* defined(__CocosAndroidStudio__EditTextFactory__) */
EditTextFactory.cpp
#include "EditTextFactory.h"
#include "EditTextAndroid.h"
#include <string>
#include "cocos2d.h"
EditTextFactory::EditTextFactory() {}
EditTextFactory* EditTextFactory::getInstance() {
static EditTextFactory instance;
return &instance;
}
EditText* EditTextFactory::createEditText() {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
auto edit = EditTextAndroid::create();
auto jobj = edit->_object;
_map.insert(std::pair<jobject, EditText*>(jobj, edit));
return edit;
#endif
return nullptr;
}
EditText* EditTextFactory::getEditTextByJobject(jobject obj) {
return _map[obj];
}
RedEditText.java
package org.red.tools;
import org.cocos2dx.lib.Cocos2dxActivity;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.FrameLayout;
public class RedEditText {
private EditText _edit;
public RedEditText() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
RedEditText.this._edit = new EditText(Cocos2dxActivity.getContext());
EditText edit = RedEditText.this._edit;
//edit.setBackgroundDrawable(null);
edit.setTextColor(Color.rgb(255, 255, 255));
edit.setMaxLines(1);
edit.setSingleLine();
edit.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
Cocos2dxActivity activity = (Cocos2dxActivity)(Cocos2dxActivity.getContext());
FrameLayout root = (FrameLayout)activity.findViewById(android.R.id.content).getRootView();
root.addView(edit);
edit.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
nativeOnTextChanged(s.toString());
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void afterTextChanged(Editable s) {}
});
}
});
}
public void setString(final String str) {
Log.e("red", str);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
_edit.setText(str);
}
});
}
public String getString() {
return _edit.getText().toString();
}
public void setContentSize(final int w, final int h) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)_edit.getLayoutParams();
params.width = w;
params.height = h;
_edit.setLayoutParams(params);
}
});
}
public void setPosition(final int x, final int y) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)_edit.getLayoutParams();
params.leftMargin = x;
params.topMargin = y;
_edit.setLayoutParams(params);
}
});
}
private native void nativeOnTextChanged(String s);
}
最后是luabinding奥帘,吐血推薦教程:http://www.cocos.com/doc/tutorial/show?id=1295
這是我綁定之后的代碼畔乙,可以直接用:
lua_RedBindings_auto.hpp
#include "base/ccConfig.h"
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
#ifndef __RedBindings_h__
#define __RedBindings_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "tolua++.h"
#ifdef __cplusplus
}
#endif
int register_all_RedBindings(lua_State* tolua_S);
#endif // __RedBindings_h__
#endif //#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
lua_RedBindings_auto.cpp
#include "lua_RedBindings_auto.hpp"
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
#include "RedBindings.h"
#include "tolua_fix.h"
#include "LuaBasicConversions.h"
int lua_RedBindings_EditText_setString(lua_State* tolua_S)
{
;
EditText* cobj = nullptr;
bool ok = true;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
#endif
#if COCOS2D_DEBUG >= 1
,,&tolua_err)) goto tolua_lerror;
#endif
cobj = (EditText*)tolua_tousertype(tolua_S,,);
#if COCOS2D_DEBUG >= 1
if (!cobj)
{
tolua_error(tolua_S,"invalid 'cobj' in function 'lua_RedBindings_EditText_setString'", nullptr);
;
}
#endif
argc = lua_gettop(tolua_S)-;
)
{
std::string arg0;
ok &= luaval_to_std_string(tolua_S, ,&arg0, "EditText:setString");
if(!ok)
{
tolua_error(tolua_S,"invalid arguments in function 'lua_RedBindings_EditText_setString'", nullptr);
;
}
cobj->setString(arg0);
lua_settop(tolua_S, );
;
}
luaL_error(tolua_S, );
;
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(tolua_S,"#ferror in function 'lua_RedBindings_EditText_setString'.",&tolua_err);
#endif
;
}
int lua_RedBindings_EditText_getString(lua_State* tolua_S)
{
;
EditText* cobj = nullptr;
bool ok = true;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
#endif
#if COCOS2D_DEBUG >= 1
,,&tolua_err)) goto tolua_lerror;
#endif
cobj = (EditText*)tolua_tousertype(tolua_S,,);
#if COCOS2D_DEBUG >= 1
if (!cobj)
{
tolua_error(tolua_S,"invalid 'cobj' in function 'lua_RedBindings_EditText_getString'", nullptr);
;
}
#endif
argc = lua_gettop(tolua_S)-;
)
{
if(!ok)
{
tolua_error(tolua_S,"invalid arguments in function 'lua_RedBindings_EditText_getString'", nullptr);
;
}
std::string ret = cobj->getString();
tolua_pushcppstring(tolua_S,ret);
;
}
luaL_error(tolua_S, );
;
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(tolua_S,"#ferror in function 'lua_RedBindings_EditText_getString'.",&tolua_err);
#endif
;
}
static int lua_RedBindings_EditText_finalize(lua_State* tolua_S)
{
printf("luabindings: finalizing LUA object (EditText)");
;
}
int lua_register_RedBindings_EditText(lua_State* tolua_S)
{
tolua_usertype(tolua_S,"EditText");
tolua_cclass(tolua_S,"EditText","EditText","cc.Node",nullptr);
tolua_beginmodule(tolua_S,"EditText");
tolua_function(tolua_S,"setString",lua_RedBindings_EditText_setString);
tolua_function(tolua_S,"getString",lua_RedBindings_EditText_getString);
tolua_endmodule(tolua_S);
std::string typeName = typeid(EditText).name();
g_luaType[typeName] = "EditText";
g_typeCast["EditText"] = "EditText";
;
}
int lua_RedBindings_EditTextFactory_getEditTextByJobject(lua_State* tolua_S)
{
;
EditTextFactory* cobj = nullptr;
bool ok = true;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
#endif
#if COCOS2D_DEBUG >= 1
,,&tolua_err)) goto tolua_lerror;
#endif
cobj = (EditTextFactory*)tolua_tousertype(tolua_S,,);
#if COCOS2D_DEBUG >= 1
if (!cobj)
{
tolua_error(tolua_S,"invalid 'cobj' in function 'lua_RedBindings_EditTextFactory_getEditTextByJobject'", nullptr);
;
}
#endif
argc = lua_gettop(tolua_S)-;
)
{
_jobject* arg0;
ok &= luaval_to_object<_jobject>(tolua_S, , "_jobject",&arg0, "EditTextFactory:getEditTextByJobject");
if(!ok)
{
tolua_error(tolua_S,"invalid arguments in function 'lua_RedBindings_EditTextFactory_getEditTextByJobject'", nullptr);
;
}
EditText* ret = cobj->getEditTextByJobject(arg0);
object_to_luaval<EditText>(tolua_S, "EditText",(EditText*)ret);
;
}
luaL_error(tolua_S, );
;
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(tolua_S,"#ferror in function 'lua_RedBindings_EditTextFactory_getEditTextByJobject'.",&tolua_err);
#endif
;
}
int lua_RedBindings_EditTextFactory_createEditText(lua_State* tolua_S)
{
;
EditTextFactory* cobj = nullptr;
bool ok = true;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
#endif
#if COCOS2D_DEBUG >= 1
,,&tolua_err)) goto tolua_lerror;
#endif
cobj = (EditTextFactory*)tolua_tousertype(tolua_S,,);
#if COCOS2D_DEBUG >= 1
if (!cobj)
{
tolua_error(tolua_S,"invalid 'cobj' in function 'lua_RedBindings_EditTextFactory_createEditText'", nullptr);
;
}
#endif
argc = lua_gettop(tolua_S)-;
)
{
if(!ok)
{
tolua_error(tolua_S,"invalid arguments in function 'lua_RedBindings_EditTextFactory_createEditText'", nullptr);
;
}
EditText* ret = cobj->createEditText();
object_to_luaval<EditText>(tolua_S, "EditText",(EditText*)ret);
;
}
luaL_error(tolua_S, );
;
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(tolua_S,"#ferror in function 'lua_RedBindings_EditTextFactory_createEditText'.",&tolua_err);
#endif
;
}
int lua_RedBindings_EditTextFactory_getInstance(lua_State* tolua_S)
{
;
bool ok = true;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
#endif
#if COCOS2D_DEBUG >= 1
,,&tolua_err)) goto tolua_lerror;
#endif
argc = lua_gettop(tolua_S) - ;
)
{
if(!ok)
{
tolua_error(tolua_S,"invalid arguments in function 'lua_RedBindings_EditTextFactory_getInstance'", nullptr);
;
}
EditTextFactory* ret = EditTextFactory::getInstance();
object_to_luaval<EditTextFactory>(tolua_S, "EditTextFactory",(EditTextFactory*)ret);
;
}
luaL_error(tolua_S, );
;
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(tolua_S,"#ferror in function 'lua_RedBindings_EditTextFactory_getInstance'.",&tolua_err);
#endif
;
}
static int lua_RedBindings_EditTextFactory_finalize(lua_State* tolua_S)
{
printf("luabindings: finalizing LUA object (EditTextFactory)");
;
}
int lua_register_RedBindings_EditTextFactory(lua_State* tolua_S)
{
tolua_usertype(tolua_S,"EditTextFactory");
tolua_cclass(tolua_S,"EditTextFactory","EditTextFactory","",nullptr);
tolua_beginmodule(tolua_S,"EditTextFactory");
tolua_function(tolua_S,"getEditTextByJobject",lua_RedBindings_EditTextFactory_getEditTextByJobject);
tolua_function(tolua_S,"createEditText",lua_RedBindings_EditTextFactory_createEditText);
tolua_function(tolua_S,"getInstance", lua_RedBindings_EditTextFactory_getInstance);
tolua_endmodule(tolua_S);
std::string typeName = typeid(EditTextFactory).name();
g_luaType[typeName] = "EditTextFactory";
g_typeCast["EditTextFactory"] = "EditTextFactory";
;
}
static int lua_RedBindings_EditTextAndroid_finalize(lua_State* tolua_S)
{
printf("luabindings: finalizing LUA object (EditTextAndroid)");
;
}
int lua_register_RedBindings_EditTextAndroid(lua_State* tolua_S)
{
tolua_usertype(tolua_S,"EditTextAndroid");
tolua_cclass(tolua_S,"EditTextAndroid","EditTextAndroid","EditText",nullptr);
tolua_beginmodule(tolua_S,"EditTextAndroid");
tolua_endmodule(tolua_S);
std::string typeName = typeid(EditTextAndroid).name();
g_luaType[typeName] = "EditTextAndroid";
g_typeCast["EditTextAndroid"] = "EditTextAndroid";
;
}
TOLUA_API int register_all_RedBindings(lua_State* tolua_S)
{
tolua_open(tolua_S);
tolua_module(tolua_S,);
tolua_beginmodule(tolua_S,"red");
lua_register_RedBindings_EditText(tolua_S);
lua_register_RedBindings_EditTextFactory(tolua_S);
lua_register_RedBindings_EditTextAndroid(tolua_S);
tolua_endmodule(tolua_S);
;
}
#endif