cocos2dx3.6 实现带光标的输入框

前端之家收集整理的这篇文章主要介绍了cocos2dx3.6 实现带光标的输入框前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

多的不说,我这个学渣,我写的代码比较搓!忍耐下吧!

CursorTextField.h

#ifndef _CursorTextField_H_
#define _CursorTextField_H_

#include "cocos2d.h"

USING_NS_CC;

class CursorTextField : public TextFieldTTF,public TextFieldDelegate,public IMEDelegate
{
private:


	// 点击开始位置
	Point m_beginPos;
	// 光标精灵
	Sprite * m_pCursorSprite;
	// 光标动画
	Action *m_pCursorAction;
	// 光标坐标
	Point m_cursorPos;
	//输入框长度
	float inputFrameWidth;
	//允许输入的最大字符数Unicode
	float inputMaxLength;
	int nLenCount;
	int codeNumType[50];    //每个字符对应的字节数量
	int codeCur;         //当前第几个字符
	int startCur;        //行开头字符下标
	int endCur;          //行末尾下标
	// 输入框总内容
	std::string m_pInputText;
	std::string inpuText; //当前输入框内容
public:
	CursorTextField();
	~CursorTextField();
	// static
	static CursorTextField * textFieldWithPlaceHolder(cocos2d::Node * node,const char *placeholder,const char *fontName,float fontSize);
	// Layer
	void onEnter();
	void onExit();
	bool init();
	// 初始化光标精灵
	void initCursorSprite(int nHeight);

	// TextFieldDelegate
	virtual bool onTextFieldAttachWithIME(TextFieldTTF *pSender) override;
	virtual bool onTextFieldDetachWithIME(TextFieldTTF * pSender) override;
	virtual bool onTextFieldInsertText(cocos2d::TextFieldTTF*  sender,const char * text,size_t nLen) override;
	virtual bool onTextFieldDeleteBackward(cocos2d::TextFieldTTF*  sender,const char * delText,size_t nLen) override;



	virtual void setPosition(const Point& pos);
	virtual void setPosition(float &x,float &y);

	void setCursorPositionX(float x); // 设置光标x位置
	// 把光标添加到和输入框一起的层中
	void AddCursor(Node *node);
	// Layer Touch
	bool onTouchBegan(Touch *pTouch,Event *pEvent);
	void onTouchEnded(Touch *pTouch,Event *pEvent);

	// 判断是否点击在TextField处
	bool isInTextField(Touch *pTouch);
	// 得到TextField矩形
	Rect getRect();

	// 打开输入法
	void openIME();
	// 关闭输入法
	void closeIME();

	std::string split_text(std::string name,int len,int start);

	const char* getInputText();
	void setInpuntText(char* text);
	void setInputWidth(float width);
	void setInputMaxLength(float length);


	cocos2d::Node * parentNode;



protected:
	EventListenerTouchOneByOne * listener;
};

#endif
CursorTextField.cpp
#include "CursorTextField.h"

#include "MyCharSet.h"

const static float DELTA = 0.5f;

using namespace cocos2d;
using namespace std;

CursorTextField::CursorTextField()
{
	TextFieldTTF();

	m_pCursorSprite = NULL;

}

CursorTextField::~CursorTextField()
{
	
}

void CursorTextField::onEnter()
{
	TextFieldTTF::onEnter();
	listener = EventListenerTouchOneByOne::create();
	listener->setSwallowTouches(true);
	listener->onTouchBegan = CC_CALLBACK_2(CursorTextField::onTouchBegan,this);
	listener->onTouchEnded = CC_CALLBACK_2(CursorTextField::onTouchEnded,this);
	Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(listener,this);
	this->setDelegate(this);
}

CursorTextField * CursorTextField::textFieldWithPlaceHolder(Node * node,float fontSize)
{
	auto pRet = new CursorTextField();
	pRet->parentNode = node;
	if (pRet && ((TextFieldTTF*)pRet)->initWithPlaceHolder(placeholder,fontName,fontSize))
	{
		pRet->autorelease();
		if (placeholder)
		{
			pRet->setPlaceHolder(placeholder);
		}
		pRet->init();
		pRet->initCursorSprite(fontSize);
		pRet->setHorizontalAlignment(kCCTextAlignmentLeft);
		return pRet;
	}
	CC_SAFE_DELETE(pRet);
	return NULL;
}

bool CursorTextField::init(){
	this->inputFrameWidth = 400;
	this->inputMaxLength = 16;
	this->nLenCount = 0;
	memset(codeNumType,sizeof(codeNumType));
	this->codeCur = 0;
	this->startCur = 0;
	this->endCur = 0;
	inpuText = "";
	return true;
}
void CursorTextField::initCursorSprite(const int mHeight)
{
	int column = 2;
	int nHeight = 20;
	int pixels[50][2];
	for (int i = 0; i < nHeight; ++i)
	{
		for (int j = 0; j < column; ++j)
		{
			pixels[i][j] = 0xffffffff;
		}
	}
	Texture2D* texture = new Texture2D();
	texture->initWithData(pixels,20,Texture2D::PixelFormat::RGB888,4,mHeight,CCSizeMake(column,nHeight));
	m_pCursorSprite = Sprite::createWithTexture(texture);
	texture->autorelease();
	if (m_pCursorSprite == nullptr)
	{
		CCLOG("NULL");
	}
	Size winSize = getContentSize();
	m_pCursorSprite->setVisible(false);
	parentNode->addChild(m_pCursorSprite);
	m_pCursorAction = RepeatForever::create(Sequence::create(FadeOut::create(0.25f),FadeIn::create(0.25f),NULL));
	m_pCursorSprite->runAction(m_pCursorAction);
}

void CursorTextField::setPosition(float &x,float &y)
{
	Point posi(x,y);
	setPosition(posi);
}

void CursorTextField::setPosition(const Point& pos)
{
	TextFieldTTF::setPosition(pos);
	// 设置光标位置
	if (NULL != m_pCursorSprite)
	{
		Size winSize = getContentSize();
		m_cursorPos = ccp(0,0/*winSize.height / 2*/);
		m_cursorPos = m_cursorPos + pos;
		m_pCursorSprite->setPosition(m_cursorPos.x,m_cursorPos.y + m_pCursorSprite->getContentSize().height / 2.0);
	}
}


void CursorTextField::setCursorPositionX(float x) // 设置光标x位置
{
	Point pt = getPosition(); // 获取输入框位置
	m_pCursorSprite->setPositionX(pt.x + x);
}
// 把光标添加到和输入框一起的层中
void CursorTextField::AddCursor(Node *node)
{
	if (NULL != node && NULL != m_pCursorSprite)
	{
		node->addChild(m_pCursorSprite);
		m_pCursorSprite->setPositionY(getContentSize().height / 2.0);
		m_pCursorSprite->runAction(m_pCursorAction);
	}
}

bool CursorTextField::onTouchBegan(cocos2d::Touch *pTouch,cocos2d::Event *pEvent)
{
	m_beginPos = pTouch->getLocation();
	return true;
}

Rect CursorTextField::getRect()
{
	Size size = getContentSize();
	return  CCRectMake(0,-size.height / 2,inputFrameWidth,size.height);
}

//获取输入框内容
const char* CursorTextField::getInputText(){
	const char* text = m_pInputText.c_str();
	return text;
}

//设置输入框内容
void CursorTextField::setInpuntText(char* text){
	m_pInputText = "";
	setString(text);
	m_pCursorSprite->setPositionX(this->getPosition().x);
	memset(codeNumType,sizeof(codeNumType));
	codeCur = 0;
	startCur = 0;
	endCur = 0;
	inpuText = "";
}

//设置输入框宽度 一旦字符串宽度超度这个长度 字符串会自动向左缩进
void CursorTextField::setInputWidth(float width){
	this->inputFrameWidth = width;
}

//设置输入宽显示的最大字符数量Unicode
void CursorTextField::setInputMaxLength(float length){
	this->inputMaxLength = length;
}

//判断点击事件,是否响应在输入框范围内
bool CursorTextField::isInTextField(cocos2d::Touch *pTouch)
{
	return getRect().containsPoint(convertTouchToNodeSpaceAR(pTouch));
}

void CursorTextField::onTouchEnded(cocos2d::Touch *pTouch,cocos2d::Event *pEvent)
{
	Point endPos = pTouch->getLocation();
	// 判断是否为点击事件
	if (::abs(endPos.x - m_beginPos.x) > DELTA ||
		::abs(endPos.y - m_beginPos.y))
	{
		// 不是点击事件
		m_beginPos.x = m_beginPos.y = -1;
		return;
	}

	// 判断是打开输入法还是关闭输入法
	isInTextField(pTouch) ? openIME() : closeIME();
}

//弹出手机键盘时响应事件
bool CursorTextField::onTextFieldAttachWithIME(cocos2d::TextFieldTTF *pSender)
{
	if (m_pInputText.empty()) {
		return false;
	}
	m_pCursorSprite->setPositionX(this->getPosition().x + getContentSize().width);
	return false;
}

//当有输入进来时响应
//@param pSender 发送事件对象
//@param text 输入内容
//@param  内容字节长度


bool CursorTextField::onTextFieldInsertText(cocos2d::TextFieldTTF* sender,size_t nLen)
{
	int j = 0 ;
	std::string mytext = text;
	for (j = 0; j < mytext.size();)
	{
		std::string sText = m_pInputText.c_str();
		wchar_t* wText = new wchar_t[200];
		char t[200];
		memset(t,sizeof(t));
		strcpy(t,sText.c_str());
		int unisize = 0;
		int cou = MyCharSet::getinstence()->utf8_to_unicode((uint8_t*)t,(uint16_t **)wText,&unisize);
		std::string ss = split_text(mytext,1,j);
		j += ss.length();
		//当字符数量超过规定值 不做处理
		if (cou >= inputMaxLength)
		{
			CC_SAFE_DELETE_ARRAY(wText);
			return true;
		}
		//return true;
		//屏蔽回车输入
		if (ss == "\n")
		{
			CC_SAFE_DELETE_ARRAY(wText);
			continue;
		}
		//输入框总内容添加
		m_pInputText.append(ss);

		
		//输入框当前字符串添加
		inpuText.append(ss);
		//当前字符的长度
		codeNumType[codeCur++] = ss.length();
		std::string localText = m_pInputText;
		setString(m_pInputText);
		//如果总字符串的长度大于指定宽度
		if (getContentSize().width > inputFrameWidth){
			//大于,截取字符串,直到字符串的长度小于指定宽度为止
			setString(inpuText);
			while (getContentSize().width > inputFrameWidth){
				int nnLen = ss.length();
				if (codeNumType[startCur] == 1){
					nnLen = 1;
				}
				if (codeNumType[startCur] == 3){
					nnLen = 3;
				}
				startCur++;
				nLenCount += nnLen;
				float gap = localText.size() - nLenCount;
				inpuText = localText.substr(nLenCount,gap);
				setString(inpuText.c_str());
				float coWidth = getContentSize().width;
			}
		}
		else{
			//小于,直接设置显示总字符串
			nLenCount = 0;
			startCur = 0;
			setString(m_pInputText);
		}
		//设置光标位置
		m_pCursorSprite->setPositionX(this->getPosition().x + getContentSize().width);
		CC_SAFE_DELETE_ARRAY(wText);
		//AndroidShowtext(mychar,1);
	}
	return true;
}


//当有输入进来时响应
//@param pSender 发送事件对象
//@param text 删除内容
//@param  内容字节长度

bool CursorTextField::onTextFieldDeleteBackward(cocos2d::TextFieldTTF* sender,size_t nLen)
{
	// 将总字符串长度减去nLen字节长
	m_pInputText.resize(m_pInputText.size() - nLen);
	//当前字符数减一
	codeNumType[codeCur--] = 0;
	std::string localText = m_pInputText;
	setString(m_pInputText);
	if (getContentSize().width > inputFrameWidth){
		//大于指定宽度,截取字符串,直到字符串长度小于指定宽度
		while (getContentSize().width > inputFrameWidth){
			int nnLen = nLen;
			if (codeNumType[startCur - 1] == 1){
				nnLen = 1;
			}
			if (codeNumType[startCur - 1] == 3){
				nnLen = 3;
			}
			nLenCount -= nnLen;
			startCur--;
			if (startCur <= 0)
				startCur = 0;
			if (nLenCount <= 0)
				nLenCount = 0;
			float gap = localText.size() - nLenCount;
			const std::string text = localText.substr(nLenCount,gap);
			setString(text);
			inpuText = text;
		}
	}
	else{
		nLenCount = 0;
		startCur = 0;
		setString(m_pInputText.c_str());
	}
	//设置光标位置
	m_pCursorSprite->setPositionX(this->getPosition().x + getContentSize().width);
	if (m_pInputText.empty()) {
		m_pCursorSprite->setPositionX(this->getPosition().x);
	}
	return true;
}

bool CursorTextField::onTextFieldDetachWithIME(cocos2d::TextFieldTTF *pSender)
{
	return false;
}

void CursorTextField::openIME()
{
	m_pCursorSprite->setVisible(true);
	setString(m_pInputText);
	((TextFieldTTF *)this)->attachWithIME();
}

void CursorTextField::closeIME()
{
	m_pCursorSprite->setVisible(false);
	//auto pTextField = (TextFieldTTF *)pRet;
	((TextFieldTTF *)this)->detachWithIME();
}

void CursorTextField::onExit()
{
	TextFieldTTF::onExit();
	Director::getInstance()->getEventDispatcher()->removeEventListener(listener);
}

std::string CursorTextField::split_text(std::string name,int start)
{
	int i = start;
	std::string str;
	if (name[i] < 0)
	{
		i++;
	}
	//while (name[i] < 0)
	//{
	//	i++;
	//	if (i - start == 2)
	//	{
	//		break;
	//	}
	//}
	if (start == i)
	{
		str = name.substr(start,1);
	}
	else
	{
		str = name.substr(start,3);
	}
	//log("mysubstr   %s",str.c_str());
	return str;
}


字节转换的

MyCharSet.h

#pragma once


#include "stdint.h"
#include "stdio.h"
#include <string.h>
#include <malloc.h>
#include <memory.h>

class MyCharSet
{
public:
	MyCharSet();
	~MyCharSet();
	static MyCharSet * getinstence();
	static void destoryinstence();
	int utf8_to_unicode(uint8_t *in,uint16_t **out,int *outsize);
	int unicode_to_utf8(uint16_t *in,int insize,uint8_t **out);
};


MyCharSet.cpp

#include "MyCharSet.h"

static MyCharSet *_MyCharSet = NULL;
MyCharSet::MyCharSet()
{
}


MyCharSet::~MyCharSet()
{
}

MyCharSet * MyCharSet::getinstence()
{
	if (_MyCharSet == NULL)
	{
		_MyCharSet = new MyCharSet();
	}
	return _MyCharSet;
}
void MyCharSet::destoryinstence()
{
	if (_MyCharSet != NULL)
	{
		delete _MyCharSet;
	}
}

int MyCharSet::utf8_to_unicode(uint8_t *in,int *outsize)
{
	uint8_t *p = in;
	uint16_t *result = NULL;
	int resultsize = 0;
	uint8_t *tmp = NULL;

	result = (uint16_t *)malloc(strlen((char *)in) * 2 + 2); /* should be enough */
	memset(result,strlen((char*)in) * 2 + 2);
	tmp = (uint8_t *)result;

	while (*p)
	{
		if (*p >= 0x00 && *p <= 0x7f)
		{
			*tmp = *p;
			tmp++;
			*tmp = '\0';
			resultsize += 1;
		}
		else if ((*p & (0xff << 5)) == 0xc0)
		{
			uint16_t t = 0;
			uint8_t t1 = 0;
			uint8_t t2 = 0;

			t1 = *p & (0xff >> 3);
			p++;
			t2 = *p & (0xff >> 2);

			*tmp = t2 | ((t1 & (0xff >> 6)) << 6);//t1 >> 2;
			tmp++;

			*tmp = t1 >> 2;//t2 | ((t1 & (0xff >> 6)) << 6);
			tmp++;

			resultsize += 1;
		}
		else if ((*p & (0xff << 4)) == 0xe0)
		{
			uint16_t t = 0;
			uint8_t t1 = 0;
			uint8_t t2 = 0;
			uint8_t t3 = 0;

			t1 = *p & (0xff >> 3);
			p++;
			t2 = *p & (0xff >> 2);
			p++;
			t3 = *p & (0xff >> 2);

			//Little Endian
			*tmp = ((t2 & (0xff >> 6)) << 6) | t3;//(t1 << 4) | (t2 >> 2);
			tmp++;

			*tmp = (t1 << 4) | (t2 >> 2);//((t2 & (0xff >> 6)) << 6) | t3;
			tmp++;
			resultsize += 1;
		}

		p++;
	}

	//*tmp = '\0';
	//tmp++;
	//*tmp = '\0';
	//resultsize += 2;

	//*out = result;
	//*outsize = resultsize;
	return resultsize;
}

int MyCharSet::unicode_to_utf8(uint16_t *in,uint8_t **out)
{
	int i = 0;
	int outsize = 0;
	int charscount = 0;
	uint8_t *result = NULL;
	uint8_t *tmp = NULL;

	charscount = insize / sizeof(uint16_t);
	result = (uint8_t *)malloc(charscount * 3 + 1);
	memset(result,charscount * 3 + 1);
	tmp = result;

	for (i = 0; i < charscount; i++)
	{
		uint16_t unicode = in[i];

		if (unicode >= 0x0000 && unicode <= 0x007f)
		{
			*tmp = (uint8_t)unicode;
			tmp += 1;
			outsize += 1;
		}
		else if (unicode >= 0x0080 && unicode <= 0x07ff)
		{
			*tmp = 0xc0 | (unicode >> 6);
			tmp += 1;
			*tmp = 0x80 | (unicode & (0xff >> 2));
			tmp += 1;
			outsize += 2;
		}
		else if (unicode >= 0x0800 && unicode <= 0xffff)
		{
			*tmp = 0xe0 | (unicode >> 12);
			tmp += 1;
			*tmp = 0x80 | (unicode >> 6 & 0x00ff);
			tmp += 1;
			*tmp = 0x80 | (unicode & (0xff >> 2));
			tmp += 1;
			outsize += 3;
		}

	}

	*tmp = '\0';
	*out = result;
	return outsize;
}


如果使用直接:

CursorTextField *m_pCursorInputLayer = CursorTextField::textFieldWithPlaceHolder(this,"click and input","fonts/Marker Felt.ttf",40);
	m_pCursorInputLayer->setAnchorPoint(ccp(0.0f,0.0f));
	m_pCursorInputLayer->setInputWidth(visibleSize.width);
	Vec2 posi(0,visibleSize.height / 2);
	m_pCursorInputLayer->setPosition(posi);
	this->addChild(m_pCursorInputLayer,1);


我这个输入解决了Android上一堆输入导致的错误,大家可以仔细去看看!
这个输入自行扩展,现在我的需求不用不需要,也就没写,大家可以自行输入。

给个思路大家吧,在切割字符的时候可以自行添加回车,我暂时想到这样来做!


我做的效果

需求来了,希望可以移动光标进行删除指定的!所以下一篇讲讲光标移动实现!

猜你在找的Cocos2d-x相关文章