爲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版, 僅供參考.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章