为Cocos2d-x增加带Button回调的系统级消息框(MessageBox)


目标: 当点击系统消息框中的 "ok" 按钮时, 可执行一段我们自己任意指定的c++代码...

实现: 修改(或添加)代码如下,


----------------------------------------------
platform/CCCommon.h

#include <functional>

// 回调类型
typedef std::function<void()> MessageBox_Callback;

// 带回调的消息框
void CC_DLL MessageBox(const char * msg, const char * title, const MessageBox_Callback & callback);


----------------------------------------------
platform/ios/CCCommon.mm

// 消息框代理
@interface MessageBox_Delegate : NSObject <UIAlertViewDelegate>
{
    MessageBox_Callback mCallback;
}
- (id)initWithCallback:(const MessageBox_Callback &)callback;
@end

@implementation MessageBox_Delegate
- (id)initWithCallback:(const MessageBox_Callback &)callback;
{
    if (self = [super init])
    {
        mCallback = callback; // 备份对象
    }
    
    return(self);
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    [alertView setDelegate: nil];
    [self autorelease];
    
    mCallback(); // 回调
}
@end

void MessageBox(const char * msg, const char * title, const MessageBox_Callback & callback)
{
    MessageBox_Delegate * modalDelegate = [[MessageBox_Delegate alloc] initWithCallback: callback];
    
    NSString * tmpTitle = (title) ? [NSString stringWithUTF8String : title] : nil;
    NSString * tmpMsg = (msg) ? [NSString stringWithUTF8String : msg] : nil;
    UIAlertView * messageBox = [[UIAlertView alloc] initWithTitle: tmpTitle
                                                          message: tmpMsg
                                                         delegate: modalDelegate
                                                cancelButtonTitle: @"OK"
                                                otherButtonTitles: nil];
    [messageBox autorelease];
    [messageBox show];
}


----------------------------------------------

platform/android/CCCommon.cpp

void MessageBox(const char * msg, const char * title)
{
    showDialogJNI(msg, title, 0); // 回调地址为0 则不回调
}

void MessageBox(const char * msg, const char * title, const MessageBox_Callback & callback)
{
    MessageBox_Callback * Callback = new MessageBox_Callback(); // 待回调后 delete
    *Callback = callback;                                       // 备份对象
    
    showDialogJNI(msg, title, (long long)Callback); // 将地址作为64位整型传给Java(防止日后将c++代码编译为64位版本)
}

extern "C"
{
    // 供Java回调
    JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxHandler_onDialogButtonClicked(JNIEnv* env, jobject thiz, jlong callback)
    {
        if (0 != callback)
        {
            MessageBox_Callback * Callback = (MessageBox_Callback *)callback;
            (*Callback)(); // 回调之
            
            delete Callback; // 删除对象
        }
    }
}


----------------------------------------------

Java_org_cocos2dx_lib_Cocos2dxHelper.h

extern void showDialogJNI(const char * pszMsg, const char * pszTitle, long long pCallback);


----------------------------------------------
Java_org_cocos2dx_lib_Cocos2dxHelper.cpp

void showDialogJNI(const char * pszMsg, const char * pszTitle, long long pCallback)
{
    if (!pszMsg)
    {
        return;
    }

    JniMethodInfo t;
    if (JniHelper::getStaticMethodInfo(t, CLASS_NAME, "showDialog", "(Ljava/lang/String;Ljava/lang/String;J)V")) // **
    {
        jstring stringArg1;

        if (!pszTitle)
        {
            stringArg1 = t.env->NewStringUTF("");
        }
        else
        {
            stringArg1 = t.env->NewStringUTF(pszTitle);
        }

        jstring stringArg2 = t.env->NewStringUTF(pszMsg);
        t.env->CallStaticVoidMethod(t.classID, t.methodID, stringArg1, stringArg2, pCallback); // 调用Java

        t.env->DeleteLocalRef(stringArg1);
        t.env->DeleteLocalRef(stringArg2);
        t.env->DeleteLocalRef(t.classID);
    }
}


----------------------------------------------

Cocos2dxHelper.java

public class Cocos2dxHelper
{
	private static void showDialog(final String pTitle, final String pMessage, final long pCallback) // 供c++调用
	{
		Cocos2dxHelper.sCocos2dxHelperListener.showDialog(pTitle, pMessage, pCallback);
	}

	public static interface Cocos2dxHelperListener // 此接口由Cocos2dxActivity实现
	{
		public void showDialog(final String pTitle, final String pMessage, final long pCallback);
	}
}


----------------------------------------------
Cocos2dxActivity.java

public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelperListener 
{
	@Override
	public void showDialog(final String pTitle, final String pMessage, final long pCallback)
	{
		Message msg = new Message();
		msg.what = Cocos2dxHandler.HANDLER_SHOW_DIALOG;
		msg.obj = new Cocos2dxHandler.DialogMessage(pTitle, pMessage, pCallback);
		this.mHandler.sendMessage(msg);
	}
}


----------------------------------------------
Cocos2dxHandler.java

public class Cocos2dxHandler extends Handler 
{
	private static LinkedList<DialogData> sDialogDataList = null;

	// c++ 回调
	public static native void onDialogButtonClicked(long callback);

	private void showDialog(Message msg) 
	{
		Cocos2dxActivity theActivity = this.mActivity.get();
		DialogMessage dialogMessage = (DialogMessage)msg.obj;
		
		AlertDialog alertDialog = new AlertDialog.Builder(theActivity)
			.setCancelable(false)
			.setTitle(dialogMessage.titile)
			.setMessage(dialogMessage.message)		
			.setPositiveButton("Ok",
				new DialogInterface.OnClickListener() 
				{					
					@Override
					public void onClick(DialogInterface dialog, int which) 
					{
						if (null != sDialogDataList)
						{
							Iterator<DialogData> listItr = sDialogDataList.iterator();
							while (listItr.hasNext()) // 遍历list找dialog
							{
								DialogData dialogData = listItr.next();
								if (dialogData.dialog == dialog)
								{								
									onDialogButtonClicked(dialogData.callback); // 回调c++
									listItr.remove(); // 移除
									break;
								}
							}
						}
					}
				})
			.create();
		
		if (null == sDialogDataList) // 初始化list
		{
			sDialogDataList = new LinkedList<DialogData>();
		}
		
		DialogData dialogData = new DialogData(alertDialog, dialogMessage.callback); // Dialog与callback绑定
		sDialogDataList.addFirst(dialogData); // 存入list (后弹出的对话框 会先被点击 所以放在list头部 便于查询)
		
		alertDialog.show();
	}

	private static class DialogData // dialog及对应的callback
	{
		public DialogInterface dialog;
		public long callback;
		
		public DialogData(DialogInterface dialog, long callback) 
		{
			this.dialog = dialog;
			this.callback = callback;
		}
	}
	
	public static class DialogMessage 
	{
		public String titile;
		public String message;
		public long callback;
		
		public DialogMessage(String title, String message, long callback) 
		{
			this.titile = title;
			this.message = message;
			this.callback = callback;
		}
	}
}


----------------------------------------------
调用实例

cocos2d::MessageBox("连接服务器失败", "通知",
    [this]()
    {
        if (GGlobal::GLoginSocket->ConnectLoginServer()) // 重新请求连接
        {
            this->mTimeUsed = 0.0f;
        }
    }
);


----------------------------------------------

以上源代码文件在不同版本的cocos2d-x中可能路径略微有差别, 可自行搜索定位, 目前只实现了Android和iOS版, 仅供参考.


发布了8 篇原创文章 · 获赞 21 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/liumazi/article/details/42082793