Cocos2d-x 3.x 头像选择器,本地相册与拍照+头像编辑功能(Android、IOS双平台实现)

来源:互联网 发布:苹果下载必备软件 编辑:程序博客网 时间:2024/05/18 17:41

大连游戏行业不是太发达,最后选择在一家应用外包公司工作,在工作和业余学习过程中积累了一点微不住道的经验,希望分享给热爱游戏的小伙伴们。

在应用开发过程中会常常有用户上传头像的功能,在网上找了N多资料发现没有人具体介绍过该用cocos2d-x实现。这篇文章就来介绍一下如何在Android和IOS平台上实现该功能。


先传一张完成后的图片一饱眼福安静:= = 怎么不好用呢~


直接上代码:

头文件 ImagePicker.h

/************************************************************************** * Copyright (c) 2015, pxbomb, All rights reserved.  * File: ImagePicker.h * Date: 2015/06/02 18:02 * Author: 田伟汉 * Email: wilhan.tian@gmail.com * Depict: 图像选择器 **************************************************************************/#ifndef _IMAGEPICKER_H_#define _IMAGEPICKER_H_#include "cocos2d.h"#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)#include "platform/android/jni/JniHelper.h"#include <jni.h>#endif// CC_PLATFORM_ANDROID/** * 图像选择器 */class ImagePicker{public:    // 获取选择器单例    static ImagePicker* getInstance();    // 销毁    static void destoryInstance();public:    // 显示本地相册与相机选择器    void callImagePickerWithPhotoAndCamera(const std::function<void(std::string)>& callback);        // 设置监听    void setListener(const std::function<void(std::string)>& callback);        // 移除监听    void removeListener();        // 打开相册    void openPhoto();        // 打开相机    void openCamera();    #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)    // 设置AppController    void setViewController(void* viewController);#endif // CC_PLATFORM_IOSprotected:    // 初始化    bool init();        ImagePicker();    protected:    std::function<void(std::string)> m_callback;    static ImagePicker* s_instance;    #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)    void* m_viewController;#endif // CC_PLATFORM_IOS    };#endif // _IMAGEPICKER_H_


实现文件 ImagePicker.cpp

#include "ImagePicker.h"//--------------------------------------------------#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)#import  "ImagePickerViewController.h"#import  "RootViewController.h"#endif//--------------------------------------------------#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)#define JAVA_CLASS              "org/cocos2dx/cpp/ImagePicker"#define JAVA_FUNC_OPEN_PHOTO    "openPhoto"#define JAVA_FUNC_OPEN_CAMERA   "openCamera"#endif//--------------------------------------------------USING_NS_CC;//--------------------------------------------------ImagePicker* ImagePicker::s_instance = NULL;//--------------------------------------------------ImagePicker* ImagePicker::getInstance(){    if (s_instance == NULL)    {        s_instance = new ImagePicker();    }    return s_instance;}//--------------------------------------------------void ImagePicker::destoryInstance(){    CC_SAFE_DELETE(s_instance);}//--------------------------------------------------ImagePicker::ImagePicker():m_callback(nullptr){    Director::getInstance()->getEventDispatcher()->addCustomEventListener("ImagePickerEvent", [=](EventCustom* eve)    {        std::string* path = (std::string*)eve->getUserData();        if (path && m_callback != nullptr)        {            m_callback(*path);        }    });}//--------------------------------------------------void ImagePicker::callImagePickerWithPhotoAndCamera(const std::function<void(std::string)>& callback){    s_instance->init();    setListener(callback);}//--------------------------------------------------void ImagePicker::setListener(const std::function<void(std::string)>& callback){    m_callback = callback;}//--------------------------------------------------void ImagePicker::removeListener(){    m_callback = nullptr;}//--------------------------------------------------void ImagePicker::openPhoto(){#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)    ImagePickerViewController* imagePickerViewController = [[ImagePickerViewController alloc] initWithNibName:nil bundle:nil];        RootViewController* _viewController = (RootViewController*)m_viewController;    [_viewController.view addSubview:imagePickerViewController.view];        [imagePickerViewController localPhoto];#endif    #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)    JniMethodInfo info;    bool ret = JniHelper::getStaticMethodInfo(info, JAVA_CLASS, JAVA_FUNC_OPEN_PHOTO,"()V");    if (ret)    {        info.env->CallStaticVoidMethod(info.classID, info.methodID);    }#endif}//--------------------------------------------------void ImagePicker::openCamera(){#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)    ImagePickerViewController* imagePickerViewController = [[ImagePickerViewController alloc] initWithNibName:nil bundle:nil];        RootViewController* _viewController = (RootViewController*)m_viewController;    [_viewController.view addSubview:imagePickerViewController.view];        [imagePickerViewController takePhoto];#endif    #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)    JniMethodInfo info;    bool ret = JniHelper::getStaticMethodInfo(info, JAVA_CLASS, JAVA_FUNC_OPEN_CAMERA,"()V");    if (ret)    {        info.env->CallStaticVoidMethod(info.classID, info.methodID);    }#endif}//--------------------------------------------------bool ImagePicker::init(){    cocos2d::Size visibleSize = Director::getInstance()->getVisibleSize();        //-------------------------------------    // 根层    //-------------------------------------    LayerColor* m_layer = LayerColor::create(Color4B(0, 0, 0, 125));    m_layer->retain();    //-------------------------------------    // 按钮背景    //-------------------------------------    Sprite* sprite = Sprite::create("ImagePicker/bk.png");    sprite->setAnchorPoint(Vec2(0.5, 0));    sprite->setPosition(Vec2(visibleSize.width/2, 0));    m_layer->addChild(sprite);    //-------------------------------------    // 按钮    //-------------------------------------    Menu* menu = Menu::create();    menu->setPosition(Vec2::ZERO);    m_layer->addChild(menu);    //-------------------------------------    MenuItemImage* btnPhoto  = MenuItemImage::create("ImagePicker/ButtonPhoto.png",  "ImagePicker/ButtonPhoto1.png",  [=](Ref* p)    {        openPhoto();    });    btnPhoto->setAnchorPoint(Vec2(0.5, 1));    btnPhoto->setPosition(Vec2(visibleSize.width / 2, 280));    menu->addChild(btnPhoto);    //-------------------------------------    MenuItemImage* btnCamera = MenuItemImage::create("ImagePicker/ButtonCamera.png", "ImagePicker/ButtonCamera1.png", [=](Ref* p)    {        openCamera();    });    btnCamera->setAnchorPoint(Vec2(0.5, 1));    btnCamera->setPosition(btnPhoto->getPosition() + Vec2(0, -btnPhoto->getContentSize().height));    menu->addChild(btnCamera);    //-------------------------------------    MenuItemImage* btnCancel = MenuItemImage::create("ImagePicker/ButtonCancel.png", "ImagePicker/ButtonCancel1.png", [=](Ref* p)    {        float height = sprite->getContentSize().height;        MoveBy* move = MoveBy::create(0.2, Vec2(0, -height));        sprite->runAction(move);        menu  ->runAction(move->clone());        Sequence* seq = Sequence::createWithTwoActions(FadeOut::create(0.2), RemoveSelf::create());        m_layer->runAction(seq);    });    btnCancel->setAnchorPoint(Vec2(0.5, 1));    btnCancel->setPosition(btnCamera->getPosition() + Vec2(0, -btnCamera->getContentSize().height - 20));    menu->addChild(btnCancel);    //-------------------------------------    // 文字    //-------------------------------------    Label* textPhoto  = Label::createWithSystemFont("Photo",  "", 24);    textPhoto->setPosition(btnPhoto->getContentSize() / 2);    textPhoto->setTextColor(Color4B::BLACK);    btnPhoto->addChild(textPhoto);    //-------------------------------------    Label* textCamera = Label::createWithSystemFont("Camera", "", 24);    textCamera->setPosition(btnPhoto->getContentSize() / 2);    textCamera->setTextColor(Color4B::BLACK);    btnCamera->addChild(textCamera);    //-------------------------------------    Label* textCancel = Label::createWithSystemFont("Cancel", "", 24);    textCancel->setPosition(btnPhoto->getContentSize() / 2);    textCancel->setTextColor(Color4B::BLACK);    btnCancel->addChild(textCancel);    //-------------------------------------    // 准备显示    //-------------------------------------    Director::getInstance()->getRunningScene()->scheduleOnce([=](float time)    {        Director::getInstance()->getRunningScene()->addChild(m_layer, INT_MAX);        m_layer->release();        float height = sprite->getContentSize().height;        sprite->setPositionY(sprite->getPositionY() - height);        menu  ->setPositionY(menu->getPositionY()   - height);        MoveBy* move = MoveBy::create(0.3, Vec2(0, height));        sprite->runAction(move);        menu  ->runAction(move->clone());        m_layer->setOpacity(0);        m_layer->runAction(FadeTo::create(0.2, 125));    }, 0.1, "ImagePickerScheduleOnce");    //-------------------------------------    // 截断事件    //-------------------------------------    EventListenerTouchOneByOne* touchEvent = EventListenerTouchOneByOne::create();    touchEvent->setSwallowTouches(true);    touchEvent->onTouchBegan = [=](Touch* touch, Event* eve)    {        if(sprite->getBoundingBox().containsPoint(touch->getLocation()))            return true;                float height = sprite->getContentSize().height;                MoveBy* move = MoveBy::create(0.2, Vec2(0, -height));        sprite->runAction(move);        menu  ->runAction(move->clone());                Sequence* seq = Sequence::createWithTwoActions(FadeOut::create(0.2), RemoveSelf::create());        m_layer->runAction(seq);                return true;    };    Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchEvent, sprite);    //-------------------------------------    return true;}//--------------------------------------------------#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)void  ImagePicker::setViewController(void* viewController){    m_viewController = viewController;}#endif//--------------------------------------------------#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)extern "C"{    void Java_org_cocos2dx_cpp_ImagePicker_onImageSaved(JNIEnv* env, jobject thiz, jstring path)    {        std::string strPath = JniHelper::jstring2string(path);        Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("ImagePickerEvent", &strPath);    }}#endif//--------------------------------------------------

为工程添加资源:略 

(图片资源和代码下载地址:点击打开链接)


分平台实现:

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

                   Android

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

1. 打开Eclipse在org.cocos2x.cpp(加入你没改过的话)包名下新建“ImagePicker.java”文件

ImagePicker.java具体代码如下:

public class ImagePicker{<span style="white-space:pre"></span>public static final int NONE = 0;    public static final int PHOTOHRAPH = 1;// 拍照    public static final int PHOTOZOOM = 2; // 缩放    public static final int PHOTORESOULT = 3;// 结果    public static final String  IMAGE_UNSPECIFIED = "image/*";        private static ImagePicker instance = null;    private static Activity    activity = null;        public static native void onImageSaved(String path);        public static ImagePicker getInstance(){    if(instance == null){    instance = new ImagePicker();    }    return instance;    }        // 初始化    public void init(Activity activity){    ImagePicker.activity = activity;    }        // 打开相册static public void openPhoto(){Intent intent = new Intent(Intent.ACTION_PICK, null);        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED);        activity.startActivityForResult(intent, PHOTOZOOM);} // 打开相机static public void openCamera(){    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(activity.getFilesDir(), "@cc_cameraCache.jpg")));        activity.startActivityForResult(intent, PHOTOHRAPH);    }// 回调public void onActivityResult(int requestCode, int resultCode, Intent data){if (resultCode == NONE)            return;                // 拍照        if (requestCode == PHOTOHRAPH) {            File picture = new File(activity.getFilesDir() + "/@cc_cameraCache.jpg");            startPhotoZoom(Uri.fromFile(picture));        }         if (data == null)            return;         // 读取相册缩放图片        if (requestCode == PHOTOZOOM) {            startPhotoZoom(data.getData());        }                // 处理结果        if (requestCode == PHOTORESOULT) {            Bundle extras = data.getExtras();            if (extras != null) {                Bitmap photo = extras.getParcelable("data");                ByteArrayOutputStream stream = new ByteArrayOutputStream();                photo.compress(Bitmap.CompressFormat.JPEG, 75, stream);                                // XXX/@ci_8888-8888-8888-8888.jpg                String path = activity.getFilesDir() + "/@ci_" + UUID.randomUUID().toString() + ".jpg";                saveMyBitmap(path, photo);                                // 通知C++层已保存图片 并返回路径                onImageSaved(path);            }        }}public void startPhotoZoom(Uri uri) {        Intent intent = new Intent("com.android.camera.action.CROP");        intent.setDataAndType(uri, IMAGE_UNSPECIFIED);        intent.putExtra("crop", "true");        intent.putExtra("aspectX", 1);        intent.putExtra("aspectY", 1);        intent.putExtra("outputX", 100);        intent.putExtra("outputY", 100);        intent.putExtra("return-data", true);        activity.startActivityForResult(intent, PHOTORESOULT);    }public void saveMyBitmap(String filePath, Bitmap mBitmap){    File f = new File(filePath);    try {    f.createNewFile();    } catch (IOException e) {    }    FileOutputStream fOut = null;    try {    fOut = new FileOutputStream(f);    } catch (FileNotFoundException e) {    e.printStackTrace();    }    mBitmap.compress(Bitmap.CompressFormat.JPEG, 70, fOut);    try {    fOut.flush();    } catch (IOException e) {    e.printStackTrace();    }    try {    fOut.close();    } catch (IOException e) {    e.printStackTrace();    }    }}

2. 在Android入口进行初始化

打开AppActivity.java文件,复写OnCreate()与onActivityResult()方法。

在OnCreate方法中对我们的类初始化:“ImagePicker.getInstance().init(this);”

在onActivityResult()中将回调参数传递到ImagePicker中:“ImagePicker.getInstance().onActivityResult(requestCode, resultCode, data);”

AppActivity.java具体代码:

public class AppActivity extends Cocos2dxActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);ImagePicker.getInstance().init(this);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// TODO Auto-generated method stubsuper.onActivityResult(requestCode, resultCode, data);ImagePicker.getInstance().onActivityResult(requestCode, resultCode, data);}}

3. 最后在AndroidManifest.xml加入访问相机权限"<uses-permission android:name="android.permission.CAMERA"/>"


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

                         IOS

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

1. 将开始创建的ImagePicker.cpp文件后缀名改为.mm文件。

2. 在proj.ioc_mac/ios文件夹下创建两个文件,分别为ImagePickerViewController.h、ImagePickerViewController.mm

ImagePickerViewController.h具体代码:

#import <UIKit/UIKit.h>@interface ImagePickerViewController : UIViewController<UINavigationControllerDelegate, UIImagePickerControllerDelegate>{    NSString* filePath;}// 打开本地相册- (void)localPhoto;// 打开相机- (void)takePhoto;@end

ImagePickerViewController.mm具体代码
#import "ImagePickerViewController.h"#import "cocos2d.h"@interface ImagePickerViewController ()@end@implementation ImagePickerViewController- (void)viewDidLoad {    [super viewDidLoad];        //[self localPhoto];}- (void)viewDidUnload{    [super viewDidUnload];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}-(void)localPhoto{    UIImagePickerController *picker = [[UIImagePickerController alloc] init];    picker.delegate      = self;    picker.sourceType    = UIImagePickerControllerSourceTypePhotoLibrary;    picker.allowsEditing = YES;    //[self presentModalViewController:picker animated:YES];    [self presentViewController:picker animated:YES completion:^(void){        NSLog(@"Imageviewcontroller is presented");    }];    [picker release];        NSLog(@"-(void)localPhoto();");}- (void)takePhoto{    UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {        UIImagePickerController* picker = [[UIImagePickerController alloc] init];        picker.delegate = self;        //设置拍照后的图像可编辑        picker.allowsEditing = YES;        picker.sourceType = sourceType;        [picker release];        [self presentModalViewController:picker animated:YES];    }    else{        NSLog(@"模拟器中无法打开照相机,请在真机中调试");    }}- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{    NSString *type = [info objectForKey:UIImagePickerControllerMediaType];        //当选择的类型是图片    if ([type isEqualToString:@"public.image"])    {        //先把图片转成NSData//        UIImage* image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];        UIImage* image = [info objectForKey:@"UIImagePickerControllerEditedImage"];        NSData *data;        if (UIImagePNGRepresentation(image) == nil)        {            data = UIImageJPEGRepresentation(image, 1.0);        }        else        {            data = UIImagePNGRepresentation(image);        }                //图片保存的路径        //这里将图片放在沙盒的documents文件夹中        NSString * DocumentsPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];                //文件管理器        NSFileManager *fileManager = [NSFileManager defaultManager];                //生成唯一字符串        NSString* uuid = [[NSUUID UUID] UUIDString];                //文件名        NSString* fileName = [NSString stringWithFormat:@"/%@.png", uuid];                //把刚刚图片转换的data对象拷贝至沙盒中 并保存为XXXXXXXX-XXXX-XXXX....XXXX.png        [fileManager createDirectoryAtPath:DocumentsPath withIntermediateDirectories:YES attributes:nil error:nil];        [fileManager createFileAtPath:[DocumentsPath stringByAppendingString:fileName] contents:data attributes:nil];                        //得到选择后沙盒中图片的完整路径        filePath = [[NSString alloc]initWithFormat:@"%@%@", DocumentsPath, fileName];                //关闭相册界面        [picker dismissModalViewControllerAnimated:YES];                std::string strFilePath = [filePath UTF8String];        cocos2d::Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("ImagePickerEvent", &strFilePath);    }    }- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{    NSLog(@"您取消了选择图片");    [picker dismissModalViewControllerAnimated:YES];}@end

3. 修改原工程AppController.mm文件,加入一行“ImagePicker::getInstance()->setViewController(_viewController);”用来初始化。

AppController.mm具体代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {        cocos2d::Application *app = cocos2d::Application::getInstance();    app->initGLContextAttrs();    cocos2d::GLViewImpl::convertAttrs();    // Override point for customization after application launch.    // Add the view controller's view to the window and display.    window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];    // Init the CCEAGLView    CCEAGLView *eaglView = [CCEAGLView viewWithFrame: [window bounds]                                         pixelFormat: (NSString*)cocos2d::GLViewImpl::_pixelFormat                                         depthFormat: cocos2d::GLViewImpl::_depthFormat                                  preserveBackbuffer: NO                                          sharegroup: nil                                       multiSampling: NO                                     numberOfSamples: 0 ];    // Use RootViewController manage CCEAGLView     _viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];    _viewController.wantsFullScreenLayout = YES;    _viewController.view = eaglView;        //----------------------------------    // 初始化ImagePicker    //----------------------------------    ImagePicker::getInstance()->setViewController(_viewController);    //----------------------------------        // Set RootViewController to window    if ( [[UIDevice currentDevice].systemVersion floatValue] < 6.0)    {        // warning: addSubView doesn't work on iOS6        [window addSubview: _viewController.view];    }    else    {        // use this method on ios6        [window setRootViewController:_viewController];    }    [window makeKeyAndVisible];        [[UIApplication sharedApplication] setStatusBarHidden:true];    // IMPORTANT: Setting the GLView should be done after creating the RootViewController    cocos2d::GLView *glview = cocos2d::GLViewImpl::createWithEAGLView(eaglView);    cocos2d::Director::getInstance()->setOpenGLView(glview);    app->run();        return YES;}



OK,接下来就是在C++代码中调用了,你只需要在想使用头像选择器的时候,调用这一行代码:
ImagePicker::getInstance()->callImagePickerWithPhotoAndCamera([=](std::string path)    {        //做你想做的事情    });
忘了说明,参数path就是你已经选择并编辑后,图片的真实路径。



咳咳,请各位大神轻喷,喜欢游戏的程序孩纸伤不起~不说了,回家LOL去了~


4 0
原创粉丝点击