你可以使用圖片名創(chuàng)建一個(gè)Sprite,可以使用預(yù)加載好的紋理創(chuàng)建一個(gè)Sprite,但是引擎沒(méi)有提供一個(gè)使用url來(lái)創(chuàng)建Sprite的方法。
在游戲中每次遇到需要從服務(wù)端獲取一個(gè)玩家的頭像url,然后通過(guò)這個(gè)url獲取玩家頭像并顯示的時(shí)候,我就會(huì)想,如果能直接用url創(chuàng)建Sprite該多好。
需要顯示配置在服務(wù)端的推廣圖片時(shí)。。。
需要顯示配置在服務(wù)端的商品列表時(shí)。。。
其實(shí)很早就想寫(xiě)這樣一個(gè)控件了,只是一直想在其之上附加各種功能(預(yù)加載? 默認(rèn)紋理? 使用本地緩存?等),導(dǎo)致自己一直想不明白要做什么,也就是需求不明確。今天終于沉下心來(lái)實(shí)現(xiàn)了一下這個(gè)URLSprite。
需求
1.使用url創(chuàng)建Sprite
2.可以設(shè)置默認(rèn)texture
3.下載好的資源保存在本地,并且可以指定文件名
4.可以使用已下載好的本地資源
大致思路
1.URLSprite繼承自Sprite
2.使用一個(gè)Texture2D指針保存默認(rèn)紋理
3.使用cocos2d引擎提供的HttpClient來(lái)下載圖片
4.使用FILE將圖片保存在本地
5.使用cocos2d引擎的FileUtils來(lái)查找本地資源
URLSprite
先來(lái)看看URLSprite的頭文件:
//
// QFLURLSprite.hpp
// MyTemplet
//
// Created by QuFangliu on 2017/1/4.
// Copyright ? 2017年 qufangliu. All rights reserved.
//
// 使用URL創(chuàng)建一個(gè)Sprite,可以設(shè)置默認(rèn)texture,對(duì)象可以自動(dòng)使用HttpClient來(lái)下載圖片資源
#ifndef QFLURLSprite_hpp
#define QFLURLSprite_hpp
#include <stdio.h>
#include "cocos2d.h"
#include "network/HttpClient.h"
/*
QFLURLSprite的狀態(tài)
*/
enum QFLURLSprite_State{
URLSprite_State_NoTexture = 0, //無(wú)紋理
URLSprite_State_Default = 1, //默認(rèn)紋理
URLSprite_State_Loaded = 2, //下載好的紋理(或者使用指定的本地文件)
};
/*
URLSprite
*/
class QFLURLSprite : public cocos2d::Sprite
{
CC_CONSTRUCTOR_ACCESS:
QFLURLSprite();
virtual ~QFLURLSprite();
public:
/*
Create
*/
static QFLURLSprite* create();
static QFLURLSprite* create(const std::string &strURL);
//指定(已)下載好的文件名,并且選擇是否直接使用本地資源
static QFLURLSprite* create(const std::string &strURL, const std::string &strFileName, bool bForceRefresh);
/*
Init
*/
virtual bool init();
virtual bool initWithURL(const std::string &strURL);
virtual bool initWithConfig(const std::string &strURL, const std::string &strFileName, bool bForceRefresh);
/*
Refresh
*/
void refresh(bool bShowDefault = false);
void loadImage();
void loadImageCallback(cocos2d::network::HttpClient* pClient, cocos2d::network::HttpResponse* pResponse);
/*
Default Texture
*/
void setDefaultTexture(cocos2d::Texture2D* pTexture);
cocos2d::Texture2D* getDefaultTexture() { return m_pDefaultTexture; }
/*
Config
*/
CC_SYNTHESIZE(std::string, m_strURL, SpriteURL); //圖片的下載地址
CC_SYNTHESIZE(std::string, m_strName, FileName); //下載好后或者指定的文件名
CC_SYNTHESIZE(bool, m_bForceRefresh, ForceRefresh); //是否強(qiáng)制刷新,false則找到本地文件就不刷新
private:
/*
tools
*/
std::string getFileNameByURL(const std::string &strURL);
std::string checkNativeFile(const std::string &strName);
cocos2d::Texture2D* m_pDefaultTexture; //默認(rèn)紋理
QFLURLSprite_State m_eState; //狀態(tài)
};
#endif /* QFLURLSprite_hpp */
創(chuàng)建方式模仿了Cocos2d引擎的Sprite的二段構(gòu)建方法,即重載不同的create方法,在create中去找對(duì)應(yīng)的init方法,真正進(jìn)行Sprite的初始化。
然后使用了一個(gè)枚舉來(lái)標(biāo)志URLSprite的狀態(tài),在setDefaultTexture時(shí),如果當(dāng)前不是使用的url指定的圖片,則顯示默認(rèn)紋理。
另外還提供了refresh方法,以供控件的重用。
上面代碼比較簡(jiǎn)單,基本都有說(shuō)明了,這里就不贅述了。
下面把cpp文件也粘貼出來(lái),懶得去看Github的童鞋可以用這個(gè),但不保證此處是最新版本。
//
// QFLURLSprite.cpp
// MyTemplet
//
// Created by QuFangliu on 2017/1/4.
// Copyright ? 2017年 qufangliu. All rights reserved.
//
#include "QFLURLSprite.hpp"
USING_NS_CC;
using namespace network;
QFLURLSprite::QFLURLSprite()
{
m_strURL = "";
m_strName = "";
m_bForceRefresh = true;
m_pDefaultTexture = nullptr;
m_eState = QFLURLSprite_State::URLSprite_State_NoTexture;
}
QFLURLSprite::~QFLURLSprite()
{
}
QFLURLSprite* QFLURLSprite::create()
{
QFLURLSprite* pSprite = new (std::nothrow) QFLURLSprite();
if (pSprite && pSprite->init()) {
pSprite->autorelease();
return pSprite;
}
else {
CC_SAFE_DELETE(pSprite);
return nullptr;
}
}
QFLURLSprite* QFLURLSprite::create(const std::string &strURL)
{
QFLURLSprite* pSprite = new (std::nothrow) QFLURLSprite();
if (pSprite && pSprite->initWithURL(strURL)) {
pSprite->autorelease();
return pSprite;
}
else {
CC_SAFE_DELETE(pSprite);
return nullptr;
}
}
QFLURLSprite* QFLURLSprite::create(const std::string &strURL, const std::string &strFileName, bool bForceRefresh)
{
QFLURLSprite* pSprite = new (std::nothrow) QFLURLSprite();
if (pSprite && pSprite->initWithConfig(strURL, strFileName, bForceRefresh)) {
pSprite->autorelease();
return pSprite;
}
else {
CC_SAFE_DELETE(pSprite);
return nullptr;
}
}
bool QFLURLSprite::init()
{
if (Sprite::init()) {
return true;
}
else {
return false;
}
}
bool QFLURLSprite::initWithURL(const std::string &strURL)
{
if (Sprite::init()) {
m_strURL = strURL;
m_strName = this->getFileNameByURL(m_strURL);
//下載圖片
this->refresh();
return true;
}
else {
return false;
}
}
bool QFLURLSprite::initWithConfig(const std::string &strURL, const std::string &strFileName, bool bForceRefresh)
{
if (Sprite::init()) {
m_strURL = strURL;
m_strName = strFileName;
m_bForceRefresh = bForceRefresh;
if (m_bForceRefresh) {
this->refresh();
}
else {
//查找紋理
auto pTexture = Director::getInstance()->getTextureCache()->getTextureForKey(strFileName);
if (pTexture) {
m_eState = QFLURLSprite_State::URLSprite_State_Loaded;
this->initWithTexture(pTexture);
}
else {
//查找本地文件
std::string strNative = this->checkNativeFile(m_strName);
if (strNative != "") {
m_eState = QFLURLSprite_State::URLSprite_State_Loaded;
this->initWithFile(strNative);
}
else {
//下載圖片
this->refresh();
}
}
}
return true;
}
else {
return false;
}
}
//下載圖片的邏輯
void QFLURLSprite::refresh(bool bShowDefault)
{
if (bShowDefault && m_pDefaultTexture) {
m_eState = QFLURLSprite_State::URLSprite_State_Default;
this->setTexture(m_pDefaultTexture);
}
else {}
if (m_strURL.empty()) {
CCLOG("Invalid url!");
return;
}
else {}
if (m_strName.empty()) {
m_strName = this->getFileNameByURL(m_strURL);
}
else {}
this->loadImage();
}
void QFLURLSprite::loadImage()
{
HttpRequest* pRequest = new (std::nothrow) HttpRequest();
if (pRequest) {
pRequest->setUrl(m_strURL.c_str());
pRequest->setRequestType(cocos2d::network::HttpRequest::Type::GET);
pRequest->setTag("LoadImage");
pRequest->setResponseCallback(CC_CALLBACK_2(QFLURLSprite::loadImageCallback, this));
HttpClient::getInstance()->send(pRequest);
pRequest->release();
//防止被刪除
CC_SAFE_RETAIN(this);
}
else {
CC_SAFE_DELETE(pRequest);
CCLOG("Can not create HttpRequest!");
}
}
void QFLURLSprite::loadImageCallback(cocos2d::network::HttpClient *pClient, cocos2d::network::HttpResponse *pResponse)
{
//和load對(duì)應(yīng)
CC_SAFE_RELEASE(this);
if (this->getReferenceCount() == 0) {
return;
}
else {}
if (pResponse) {
if (pResponse->isSucceed()) {
//保存請(qǐng)求的圖片數(shù)據(jù)
std::vector<char>* pBuffer = pResponse->getResponseData();
std::string strBuffer = std::string(pBuffer->begin(), pBuffer->end());
std::string strPath = FileUtils::getInstance()->getWritablePath() + m_strName;
//圖片保存到本地
FILE *pFile = fopen(strPath.c_str(), "wb+");
fwrite(strBuffer.c_str(), 1, strBuffer.size(), pFile);
fclose(pFile);
//使用下載的圖片
m_eState = QFLURLSprite_State::URLSprite_State_Loaded;
this->setTexture(strPath);
}
else {
CCLOG("Request error:%s", pResponse->getErrorBuffer());
}
}
else {
CCLOG("Request failed!");
}
}
void QFLURLSprite::setDefaultTexture(cocos2d::Texture2D *pTexture)
{
m_pDefaultTexture = pTexture;
if (m_eState != QFLURLSprite_State::URLSprite_State_Loaded) {
m_eState = QFLURLSprite_State::URLSprite_State_Default;
this->initWithTexture(m_pDefaultTexture);
}
else {}
}
std::string QFLURLSprite::getFileNameByURL(const std::string &strURL)
{
return strURL.substr(strURL.find_last_of("/") + 1);
}
std::string QFLURLSprite::checkNativeFile(const std::string &strName)
{
std::string strPath = "";
//查找項(xiàng)目資源
strPath = FileUtils::getInstance()->fullPathForFilename(strName);
if (FileUtils::getInstance()->isFileExist(strPath)) {
return strPath;
}
else {}
//查找讀寫(xiě)路徑下的資源
strPath = FileUtils::getInstance()->getWritablePath() + strName;
if (FileUtils::getInstance()->isFileExist(strPath)) {
return strPath;
}
else {}
return "";
}
代碼比較簡(jiǎn)單,也沒(méi)有周詳?shù)娜ハ朊恳粋€(gè)細(xì)節(jié)。例如如果url指向的不是一個(gè)可用的圖片,而是一個(gè)mp3文件,要如何處理?寫(xiě)文件很慢要不要另外啟動(dòng)一個(gè)異步線程來(lái)做?
這些需要的時(shí)候再優(yōu)化啦~
如果小伙伴們發(fā)現(xiàn)有問(wèn)題,或者有更好的實(shí)現(xiàn)方式,或者其他建議,歡迎聯(lián)系噢~
下一個(gè)UI就做個(gè)道具列表吧。