cocos2dx 3.2键盘操控的列表页的初步实现
一、实现后的目标效果 有图有真相,首先上实现了的效果。 二 、思路 由于要加载较多数据,那么为了使得界面更近流畅,我采用TableView,其中他的Cell是可以复用的。创建10000个也是秒秒钟的事情。 那么使用上下排列的TableView,每个cell自定义三个Item即可
一、实现后的目标效果
有图有真相,首先上实现了的效果。
二 、思路
由于要加载较多数据,那么为了使得界面更近流畅,我采用TableView,其中他的Cell是可以复用的。创建10000个也是秒秒钟的事情。
那么使用上下排列的TableView,每个cell自定义三个Item即可,当然也可以N个,可以自己写好接口。
由于我们想使得tableView可以滚动到指定的cell位置,也就是一格一格滚动,那么我们最好自定义一个tableView继承于系统的tableView.
三 、实现步骤
如果你对于TableView不太熟悉,建议先看官方Testcpp例子.
如果你比较熟悉,那么我就不废话,继续往下讲了。
我们先来自定义一个TableViewcell。也就是自定义一行的内容。我相信这个非常简单。
四、准备工作
我们先来自定义一个TableViewcell。也就是自定义一行的内容。我相信这个非常简单。
cell头文件
class XTableViewCell : public cocos2d::extension::TableViewCell { public: XTableViewCell(); virtual ~XTableViewCell(); CREATE_FUNC(XTableViewCell); /************************************************************************/ /* update item by data */ /************************************************************************/ bool updateItemData(const unsigned int tag, const std::string icon, const std::string name, const std::string size, const std::string downnum, const std::string score); bool setItemSelected(const unsigned int tag,bool isSeleted); CC_CONSTRUCTOR_ACCESS: bool init(); //bool init bool initLayout(); void update(float t); private: cocos2d::Size _cellSize; //the size of cell unsigned char _itemNum; // the number of item };
cell .源文件
///////////////////////////////////////////////////////////////////////////////////////////// /***************************CustomTableViewCell Class**************************************/ //////////////////////////////////////////////////////////////////////////////////////////// XTableViewCell::XTableViewCell():_itemNum(3),_cellSize(Size(1920,275)) { } XTableViewCell::~XTableViewCell() { } bool XTableViewCell::init() { IF_NULL_RETURN_FALSE(Node::init()); IF_NULL_RETURN_FALSE(initLayout()); //scheduleUpdate(); //resumeSchedulerAndActions(); return true; } bool XTableViewCell::initLayout() { auto lout = ui::Layout::create(); IF_NULL_RETURN_FALSE(lout); lout->setLayoutType(ui::Layout::Type::ABSOLUTE); lout->setTouchEnabled(true); lout->setLoopFocus(false); lout->setPassFocusToChild(true); lout->setContentSize(Size(_cellSize.width,200.0f)); this->addChild(lout); lout->setTag(100); lout->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT); lout->setPosition(Vec2(0,75)); for(int j =0;j<_itemnum const std::string txt='StringUtils::format("%dt%d",0,j);//名称后面得重新修改' griditem item="GridItem::create();" if_null_return_false item->setPosition(Vec2(j*600+90,0)); item->setName(txt); lout->addChild(item,1,j); } return true; } void XTableViewCell::update( float t ) { log("XTableViewCell::update"); } bool XTableViewCell::updateItemData( const unsigned int tag, const std::string icon, const std::string name, const std::string size, const std::string downnum, const std::string score ) { auto lout = this->getChildByTag(100); IF_NULL_RETURN_FALSE(lout); auto item = (GridItem*)lout->getChildByTag(tag); IF_NULL_RETURN_FALSE(item); if(""!=icon) { item->updateIcon(icon); } if(""!=name) { item->updateName(name); } if(""!=size) { item->updateSize(size); } if(""!=downnum) { item->updateDownNum(downnum); } if(""!=score) { item->updateScore(score); } return true; } bool XTableViewCell::setItemSelected( const unsigned int tag,bool isSeleted ) { auto lout = this->getChildByTag(100); IF_NULL_RETURN_FALSE(lout); auto item = (GridItem*)lout->getChildByTag(tag); IF_NULL_RETURN_FALSE(item); item->setSelected(isSeleted); return true; }</_itemnum>
里面都实现了什么,其实就是简单的添加了三个自定义Item.
然后,我们自定义一个TableView实现了两个方法。
一个是去实现滚动到指定cell的方法。
另外一个是我使用触摸的时候需要获得当前使用的cell去判断哪个Item位置位于触摸位置。
我们这里只讲键盘的。那么你可能就用不到这个函数了。
代码如下:
class XTableView : public cocos2d::extension::TableView { public: /** * @brief scroll to the Designated cell * @param index --- the idx of Designated cell **/ void scrollToCellIndex(ssize_t index); /*************************************************** * @decripition if you need Analyzing touch item , * maby you will use this function to get used cell ****************************************************/ cocos2d::Vector<:extension::tableviewcell> getCurrentCells() const; };</:extension::tableviewcell>
///////////////////////////////////////////////////////////////////////////////////////////// /***************************XTableView Class**************************************/ //////////////////////////////////////////////////////////////////////////////////////////// void XTableView::scrollToCellIndex( ssize_t index ) { this->getContainer()->stopAllActions(); Vec2 offset = _offsetFromIndex(index)*-1; Vec2 maxOffSet = this->maxContainerOffset(); Vec2 minOffSet = this->minContainerOffset(); float offX = MIN(offset.x,maxOffSet.x); offX = MAX(offX,minOffSet.x); float offY = MIN(offset.y,maxOffSet.y); offY = MAX(offY,minOffSet.y); this->setContentOffset(Vec2(offX,offY),true); } cocos2d::Vector<:extension::tableviewcell> XTableView::getCurrentCells() const { log("used cell count is %d",_cellsUsed.size()); return this->_cellsUsed; }</:extension::tableviewcell>
好了,那么接下来的重点是列表页的实现。
五、页面具体实现
由于篇幅受限,代码内容比较多,相信大家自己分析就能理解,那么先就不废话了,先上代码吧。不懂的或者有好的建议希望可以留言讨论。
头文件。(注:具体数据录入,我自己的已删除,需要的可以添加自己的数据,现在展示的基本只是一个界面)
enum class POS_TYPE { TYPE_0,// right, down and scroll up TYPE_1,//left,right, down and scroll up TYPE_2,//left, down and scroll up TYPE_3,// right,up,down TYPE_4,//left,right,up,down TYPE_5,//left, up,down TYPE_6,// right,up, and scroll down TYPE_7,//left,right,up, and scroll down TYPE_8,//left, up, and scroll down TYPE_9 // can do nothing }; enum class CHANGE_TYPE { LEFT, RIGHT, UP, DOWN, UP_SCROLL, DOWN_SCROLL, NOTHING }; typedef struct { //item idx ,and start from value 0 to _pageX unsigned char idx; //cell idx unsigned int cellIdx; // selected state bool isSelected; /***************************************** * pos in screen like a matrix,such as * (0,0),(1,0),(2,0) * (0,1),(1,1),(2,1) * (0,2),(1,2),(2,2) *****************************************/ unsigned char posX; unsigned char posY; POS_TYPE posType; }itemState; class XGridView :public cocos2d::Layer, public cocos2d::extension::TableViewDataSource, public cocos2d::extension::TableViewDelegate { public: CREATE_FUNC(XGridView); /*** *@brief create a GridView *@ ***/ virtual void scrollViewDidScroll(cocos2d::extension::ScrollView* view); virtual void scrollViewDidZoom(cocos2d::extension::ScrollView* view); virtual void tableCellTouched(cocos2d::extension::TableView* table, cocos2d::extension::TableViewCell* cell); virtual cocos2d::Size tableCellSizeForIndex(cocos2d::extension::TableView *table, ssize_t idx); virtual cocos2d::extension::TableViewCell* tableCellAtIndex(cocos2d::extension::TableView *table, ssize_t idx); virtual ssize_t numberOfCellsInTableView(cocos2d::extension::TableView *table); CC_CONSTRUCTOR_ACCESS: XGridView(); virtual ~XGridView(); virtual bool init(); virtual bool initWithDatas(ssize_t cellTotalNum,const cocos2d::Size tableSize); virtual bool initMoveFoucus(); virtual bool initTable(); virtual bool initProgressBar(); virtual bool initKeyListen(); virtual void initStateMatrix(); virtual void keyHandler(cocos2d::EventKeyboard::KeyCode key); virtual bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *unused_event); virtual void onTouchMoved(cocos2d::Touch *touch, cocos2d::Event *unused_event); virtual void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *unused_event); virtual void onTouchCancelled(cocos2d::Touch *touch, cocos2d::Event *unused_event); virtual void listenItemTouch(cocos2d::Touch *touch, cocos2d::Event *unused_event); void updateBySceenState(); virtual void isItemTouched(cocos2d::Node* item,const cocos2d::Vec2 point); virtual void deCodeByJson(); void update(float t); virtual void onEnterTransitionDidFinish(); //some model function bool isSelectedByIdx(ssize_t mIdx) const; void updateSceenStateByKey(cocos2d::EventKeyboard::KeyCode key); POS_TYPE getPosTypeByXY(unsigned int X_i,unsigned int Y_j); itemState* getSelectedItemState() const; CHANGE_TYPE getChangeType(POS_TYPE posType,cocos2d::EventKeyboard::KeyCode key); void updateMoveFoucs(cocos2d::EventKeyboard::KeyCode key,POS_TYPE pos); void loadPageNumData(unsigned int cellIndx); void keyListenDelay(float t); void updateDalay(float t); void onExit() override; // update cell at idx void updateCellAtIdx(ssize_t idx); // update Item At idx void updateItemAtIdx(ssize_t idx); private: XTableView* _mTable; cocos2d::Sprite* _progressBar; ssize_t _cellTotalNum; cocos2d::Size _tableSize; ssize_t _pageX; ssize_t _pageY; std::vector<:string> _iconImg; std::vector<:string> _appName; std::vector<:string> _appSize; std::vector<:string> _downNum; std::vector<:string> _appScore; //the state of screen,true means selected and false means unselected std::vector<itemstate> _screenState; //the cell of selected idx ssize_t _currentCellIdx; //item idx which in cell unsigned char _selectedItmIdx; bool _isdecoded; unsigned int _itemTotalNum; std::atomic_bool _firstPageUpdate[9]; cocos2d::Vec2 _pos[9]; cocos2d::Sprite* _moveFoucus; bool _keyContrl; long _scrollTime; bool _updateCell; };</itemstate></:string></:string></:string></:string></:string>
USING_NS_CC; USING_NS_CC_EXT; char* dataIndex[]= { "allnum", "appico", //APP ICO Image "apptitle", //APP Name "downnum", //APP Down times "score" , //APP Score "appSize" //APP size }; XGridView::XGridView():_mTable(nullptr),_progressBar(nullptr), _cellTotalNum(100),_tableSize(Size(1920.0f,960.0f)),_moveFoucus(nullptr), _pageX(3),_pageY(3),_gridId(0),_isdecoded(false),_keyContrl(true),_currentCellIdx(0), _selectedItmIdx(0),_itemTotalNum(300),_loadNum(0),_scrollTime(0L),_updateCell(true) { } XGridView::~XGridView() { CC_SAFE_RELEASE(_mTable); CC_SAFE_RELEASE(_progressBar); } bool XGridView::init() { IF_RETURN_FALSE(!initWithDatas(_cellTotalNum,_tableSize)); return true; } bool XGridView::initWithDatas(ssize_t cellTotalNum,const Size tableSize ) { IF_NULL_RETURN_FALSE(Layer::init()); setData(_json); _cellTotalNum = cellTotalNum; _tableSize = tableSize; IF_NULL_RETURN_FALSE(initKeyListen()); IF_NULL_RETURN_FALSE(initMoveFoucus()); IF_NULL_RETURN_FALSE(initTable()); IF_NULL_RETURN_FALSE(initProgressBar()); initStateMatrix(); deCodeJsonById(); return true; } void XGridView::tableCellTouched(TableView* table,TableViewCell* cell ) { log("cell touched at index: %ld", cell->getIdx()); auto lout = (ui::Layout*)cell->getChildByTag(100); IF_RETURN(!lout); for(auto &item : lout->getChildren()) { if(!item) continue; else { if(item==lout->getCurrentFocusedWidget(true)) { ((GridItem*)item)->setSelected(true); //_selectedIdx = cell->getIdx()*_pageX+item->getTag(); } else { ((GridItem*)item)->setSelected(false); } } } } Size XGridView::tableCellSizeForIndex(TableView *table, ssize_t idx ) { return Size(_tableSize.width, _tableSize.height/_pageY); } TableViewCell* XGridView::tableCellAtIndex(TableView *table, ssize_t idx ) { auto string = String::createWithFormat("%ld", idx); TableViewCell *cell = table->dequeueCell(); if (!cell) { cell = XTableViewCell::create(); IF_RETURN_P(!cell,nullptr); cell->autorelease(); return cell; for(unsigned char i=0;i<_pagex if_null_continue ssize_t itemidx="idx*_pageX+i;" if_continue>_iconImg.size()-1||itemIdx>_appName.size()-1); ((XTableViewCell*)cell)->updateItemData(i,_iconImg.at(itemIdx),_appName.at(itemIdx),"5.03M","","7.6"); ((XTableViewCell*)cell)->setItemSelected(i,idx==_currentCellIdx&&i==_selectedItmIdx); } auto label = Label::createWithSystemFont(string->getCString(), "Helvetica", 40.0); IF_NULL_RETURN_P(label,cell); label->setPosition(Vec2::ZERO); label->setAnchorPoint(Vec2::ZERO); label->setTag(123); cell->addChild(label); } else { auto _cellChild = cell->getChildByTag(100); for(unsigned char i=0;i<_pagex if_null_continue ssize_t itemidx="idx*_pageX+i;" if_continue>_iconImg.size()-1||itemIdx>_appName.size()-1); ((XTableViewCell*)cell)->updateItemData(i,_iconImg.at(itemIdx),_appName.at(itemIdx),"5.03M","","7.6"); ((XTableViewCell*)cell)->setItemSelected(i,idx==_currentCellIdx&&i==_selectedItmIdx); } auto label = (Label*)cell->getChildByTag(123); IF_RETURN_P(!label,cell); label->setString(string->getCString()); } return cell; } ssize_t XGridView::numberOfCellsInTableView(TableView *table ) { return _cellTotalNum; } bool XGridView::initTable() { _mTable = (XTableView*)TableView::create(this,_tableSize); IF_RETURN_FALSE(!_mTable); _mTable->setDirection(ScrollView::Direction::VERTICAL); _mTable->setDelegate(this); this->addChild(_mTable); _mTable->setVerticalFillOrder(TableView::VerticalFillOrder::TOP_DOWN); _mTable->reloadData(); return true; } void XGridView::scrollViewDidScroll( cocos2d::extension::ScrollView* view ) { Vec2 pos = view->getContentOffset(); Vec2 _pos = view->getContentSize()-view->getViewSize(); float percent = -(pos.y/_pos.y); // log("scroll percent is : %f", percent); IF_NULL_RETURN(_progressBar); _progressBar->setPositionY(960/2-600/2 +_progressBar->getScaleY()*_progressBar->getContentSize().height +600*percent*(1-_progressBar->getScaleY())); } void XGridView::scrollViewDidZoom( cocos2d::extension::ScrollView* view ) { } bool XGridView::onTouchBegan( Touch *touch, Event *unused_event ) { return true; } void XGridView::onTouchMoved( Touch *touch, Event *unused_event ) { } void XGridView::onTouchEnded( Touch *touch, Event *unused_event ) { listenItemTouch(touch,unused_event); } void XGridView::onTouchCancelled( Touch *touch, Event *unused_event ) { } void XGridView::listenItemTouch( Touch *touch, Event *unused_event ) { auto touchPoint = touch->getLocationInView(); touchPoint = Director::getInstance()->convertToGL(touchPoint); for(auto &e:_mTable->getCurrentCells()) { IF_NULL_CONTINUE(e); log("cell[%d]",e->getIdx()); auto lout = e->getChildByTag(100); IF_NULL_CONTINUE(lout); if(dynamic_cast<:layout>(lout)) { for (auto item:((ui::Layout*)lout)->getChildren()) { isItemTouched(item,touchPoint); } } } } void XGridView::isItemTouched( cocos2d::Node* item,const cocos2d::Vec2 point ) { IF_RETURN(!item); auto gItem = dynamic_cast<griditem>(item); IF_RETURN(!gItem); auto acP = gItem->getAnchorPoint();//item锚点 auto itemPos = gItem->getPosition();//item相对父容器的pos itemPos = gItem->getParent()->convertToWorldSpaceAR(itemPos);//相对于世界的位置 auto itemSize = gItem->getContentSize(); auto itemRect = Rect(itemPos.x,itemPos.y,itemSize.width,itemSize.height); if(itemRect.containsPoint(point)) { gItem->setSelected(true); //_selectedIdx = gItem->getIdx(); //log("_selectedIdx=%d",_selectedIdx); } else { gItem->setSelected(false); } } bool XGridView::initProgressBar() { auto barBg = Sprite::create("grid/progress_bg.png"); IF_NULL_RETURN_FALSE(barBg); barBg->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT); barBg->setPosition(90+600+600+500+80,960/2-600/2); addChild(barBg); _progressBar = Sprite::create("grid/progress_pre.png"); IF_NULL_RETURN_FALSE(_progressBar); _progressBar->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT); addChild(_progressBar); float scaleY = 1; if(_cellTotalNum>_pageY) { //float s = _pageY/_cellTotalNum; scaleY = MAX(_pageY/(_cellTotalNum*1.0f),0.02f); } _progressBar->setScaleY(scaleY); _progressBar->setPosition(90+600+600+500+80,960/2-600/2 +_progressBar->getScaleY()*_progressBar->getContentSize().height +600*1*(1-_progressBar->getScaleY())); return true; } bool XGridView::initKeyListen() { auto listener = EventListenerKeyboard::create(); IF_NULL_RETURN_FALSE(listener); listener->onKeyReleased = [=](EventKeyboard::KeyCode key,Event* event){ keyHandler(key); }; this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener,this); return true; } void XGridView::keyHandler(EventKeyboard::KeyCode key ) { updateSceenStateByKey(key); updateBySceenState(); } void XGridView::initStateMatrix() { IF_NOEMPTY_CLEAR(_screenState); for (unsigned int i = 0; i posType; auto change_Type = getChangeType(p,key); updateMoveFoucs(key,p); auto maxIdx = _screenState.size(); switch (change_Type) { case CHANGE_TYPE::LEFT: log("left"); _selectedItmIdx--; for (unsigned int i = 0;i<maxidx _screenstate _currentcellidx _mtable->updateCellAtIndex(_currentCellIdx); break; case CHANGE_TYPE::RIGHT: log("right"); _selectedItmIdx++; for (unsigned int i = 0;i<maxidx _screenstate _currentcellidx _mtable->updateCellAtIndex(_currentCellIdx); break; case CHANGE_TYPE::UP: log("up"); _currentCellIdx --; for (unsigned int i = 0;i<maxidx _screenstate _currentcellidx _mtable->updateCellAtIndex(_currentCellIdx+1); _mTable->updateCellAtIndex(_currentCellIdx); break; case CHANGE_TYPE::DOWN: log("down"); _currentCellIdx++; for (unsigned int i = 0;i<maxidx _screenstate _currentcellidx _mtable->updateCellAtIndex(_currentCellIdx-1); _mTable->updateCellAtIndex(_currentCellIdx); break; case CHANGE_TYPE::UP_SCROLL: if (!_keyContrl) { return; } if(_keyContrl) { _keyContrl = false; scheduleOnce(schedule_selector(XGridView::keyListenDelay), 0.05f); } log("up_scroll"); _currentCellIdx--; for (unsigned int i = 0;i<maxidx _screenstate _currentcellidx _scrolltime="getCurrentMillionTime();" _mtable->scrollToCellIndex(_currentCellIdx+2); _mTable->updateCellAtIndex(_currentCellIdx+2); _mTable->updateCellAtIndex(_currentCellIdx+1); _mTable->updateCellAtIndex(_currentCellIdx); return; case CHANGE_TYPE::DOWN_SCROLL: if (!_keyContrl) { return; } if(_keyContrl) { _keyContrl = false; scheduleOnce(schedule_selector(XGridView::keyListenDelay), 0.05f); } log("down_scroll"); _currentCellIdx ++; for (unsigned int i = 0;i<maxidx _screenstate _currentcellidx _scrolltime="getCurrentMillionTime();" _mtable->scrollToCellIndex(_currentCellIdx); _mTable->updateCellAtIndex(_currentCellIdx-2); _mTable->updateCellAtIndex(_currentCellIdx-1); _mTable->updateCellAtIndex(_currentCellIdx); return; case CHANGE_TYPE::NOTHING: log("nothing"); return; default: log("default"); return; } //_mTable->reloadData(); } POS_TYPE XGridView::getPosTypeByXY( unsigned int X_i,unsigned int Y_j ) { // if(0==X_i&&0==Y_j) return POS_TYPE::TYPE_0; if(0<x_i return pos_type::type_1 if pos_type::type_2>Y_j) return POS_TYPE::TYPE_3; if(0<x_i>Y_j) return POS_TYPE::TYPE_4; if(_pageX-1==X_i&&0<y_j>Y_j) return POS_TYPE::TYPE_5; // if(0==X_i&&_pageY-1==Y_j) return POS_TYPE::TYPE_6; if(0<x_i return pos_type::type_7 if pos_type::type_8 pos_type::type_9 itemstate xgridview::getselecteditemstate const for e:_screenstate nullptr change_type xgridview::getchangetype pos_type postype key auto pos="(int)posType;" switch case eventkeyboard::keycode change_type::left break change_type::right change_type::up change_type::up_scroll change_type::down _celltotalnum-1 change_type::down_scroll change_type::nothing void xgridview::updatebysceenstate>reloadData(); } void XGridView::deCodeJsonById() { // do some thing to initialize data //... _isdecoded = true; } void XGridView::handlerValueChangge(float t) { for (unsigned char i=0;i<once_load_num if _firstpageupdate false _mtable->updateCellAtIndex(i/_pageX); } } } void XGridView::update( float t ) { Layer::update(t); } void XGridView::onEnterTransitionDidFinish() { Layer::onEnterTransitionDidFinish(); scheduleUpdate(); schedule(schedule_selector(XGridView::updateDalay),0.2f); } bool XGridView::initMoveFoucus() { _moveFoucus = Sprite::create("grid/focus.png"); IF_NULL_RETURN_FALSE(_moveFoucus); addChild(_moveFoucus); _moveFoucus->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT); //_moveFoucus->setPosition(500,500); for (unsigned char i=0;isetPosition(_pos[0]); return true; } void XGridView::updateMoveFoucs( EventKeyboard::KeyCode key,POS_TYPE pos ) { int mPos = (int)pos; float time = 0.1f; int nextPos = -1; switch (key) { case EventKeyboard::KeyCode(KEY_LEFT): if (mPos%_pageX) { nextPos = mPos - 1; } break; case EventKeyboard::KeyCode(KEY_RIGHT): if ((mPos+1)%_pageX) { nextPos = mPos + 1; } break; case EventKeyboard::KeyCode(KEY_UP): if (mPos>_pageX-1) { nextPos = mPos - _pageX; } break; case EventKeyboard::KeyCode(KEY_DOWN): if (mPos<_pagex nextpos="mPos" _pagex break default: if _movefoucus->stopAllActions(); _moveFoucus->runAction(MoveTo::create(time,_pos[nextPos])); } } void XGridView::loadPageNumData(unsigned int cellIndx) { //load data of cell } void XGridView::keyListenDelay( float t ) { _keyContrl = true; } void XGridView::updateDalay( float t ) { if(getCurrentMillionTime()-_scrollTime>500) { loadPageNumData(_currentCellIdx); } } void XGridView::onExit() { NotificationCenter::getInstance()->removeAllObservers(this); this->unscheduleAllSelectors(); Layer::onExit(); } void XGridView::updateCellAtIdx( ssize_t idx ) { for (unsigned int i = idx*_pageX;i<br> <p> </p> <p> <span>http://blog.csdn.net/q229827701/article/details/40619697</span></p> <br> </_pagex></once_load_num></x_i></y_j></x_i></x_i></maxidx></maxidx></maxidx></maxidx></maxidx></maxidx></griditem></:layout></_pagex></_pagex>

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

According to news from this site on August 12, VGN launched the co-branded "Elden Ring" keyboard and mouse series on August 6, including keyboards, mice and mouse pads, designed with a customized theme of Lani/Faded One. The current series of products It has been put on JD.com, priced from 99 yuan. The co-branded new product information attached to this site is as follows: VGN丨Elden Law Ring S99PRO Keyboard This keyboard uses a pure aluminum alloy shell, supplemented by a five-layer silencer structure, uses a GASKET leaf spring structure, has a single-key slotted PCB, and the original height PBT material Keycaps, aluminum alloy personalized backplane; supports three-mode connection and SMARTSPEEDX low-latency technology; connected to VHUB, it can manage multiple devices in one stop, starting at 549 yuan. VGN丨Elden French Ring F1PROMAX wireless mouse the mouse

How to implement dual WeChat login on Huawei mobile phones? With the rise of social media, WeChat has become one of the indispensable communication tools in people's daily lives. However, many people may encounter a problem: logging into multiple WeChat accounts at the same time on the same mobile phone. For Huawei mobile phone users, it is not difficult to achieve dual WeChat login. This article will introduce how to achieve dual WeChat login on Huawei mobile phones. First of all, the EMUI system that comes with Huawei mobile phones provides a very convenient function - dual application opening. Through the application dual opening function, users can simultaneously

How to set the skin for WeChat keyboard? WeChat Keyboard is a very smart mobile phone input method software. This software has many user-friendly functions. It allows users to choose their own input mode and find the expressions they want as quickly as possible on this software. send out. This software also allows users to change the skin of the keyboard themselves. Many users are not sure how to change the skin. The editor below has compiled the skin changing methods for your reference. How to set the WeChat keyboard skin In WeChat, SMS or other applications that require the use of the keyboard on your phone, you can click the input method settings icon in the upper left corner of the keyboard to enter the settings page to view the function setting options for various input methods. 2. Click "Personalized Skin" on the settings page of the input method.

According to news from this website on February 29, Maicong today launched two versions of "Hyacinth Switch" and "Glazed Ice Cream Switch" for the K87 three-mode mechanical keyboard. The keyboard features "Gasket structure, 80% arrangement", related shaft keyboards The price information is as follows: "Hyacinth Switch" version: initial price is 299 yuan. "Liuguang Ice Cream Switch" version: initial price is 379 yuan. According to reports, the series of keyboards use Gasket structure, 87-key 80% arrangement, full-key rollover, and support thermal For plugging and unplugging, it claims to use "original/MDA two-color PBT keycaps", uses a 1.2mm single-key slotted PCB (lower lamp position), is equipped with RGB lighting effects, and has a magnetic absorption nameplate design. In addition, this keyboard is equipped with a 6000 mAh battery and a wireless delay of 3ms. The official size and size of the keyboard have not been announced.

Apple mobile keyboard users want to set up the handwriting input method, but don’t know how to do it. It’s actually very simple. Users can directly select the handwriting input method in the phone’s keyboard settings. If not, they can also manually add a handwriting input method. How to set the handwriting input method on the Apple mobile phone keyboard A: Enable the handwriting input method directly in the keyboard settings 1. When Apple users use the input method, the handwriting input method is enabled by default. 2. Users only need to click and hold the lower left corner to select the handwriting input method while typing. 3. If the user does not have a handwriting input method in his mobile phone, he can also add it manually. 4. The user enters the settings, finds the universal keyboard settings, and adds the handwriting input option to the first keyboard. 5. Use handwriting input method to

How to implement the WeChat clone function on Huawei mobile phones With the popularity of social software and people's increasing emphasis on privacy and security, the WeChat clone function has gradually become the focus of people's attention. The WeChat clone function can help users log in to multiple WeChat accounts on the same mobile phone at the same time, making it easier to manage and use. It is not difficult to implement the WeChat clone function on Huawei mobile phones. You only need to follow the following steps. Step 1: Make sure that the mobile phone system version and WeChat version meet the requirements. First, make sure that your Huawei mobile phone system version has been updated to the latest version, as well as the WeChat App.

According to news from this website on July 19, Lingbao K87/PRO three-mode mechanical keyboard will be on sale at 8 o'clock tonight. The main differences between the two versions are the shaft/color/battery differences. The standard version is equipped with 4000 mAh. Battery, the PRO version is equipped with an 8000 mAh battery. The price information compiled by this website is as follows: K87 Light Cloud White: 99 yuan K87 Night Purple/Xiaguang Purple/Sunny Mountain Blue: 149 yuan K87 Dust Gray/Star Daisy Purple: 199 yuan K87PRO : 249 yuan According to reports, this keyboard adopts a Gasket structure, uses an 80% arrangement layout, is available in a variety of colors, has built-in lower light RGB lights, and supports three-mode connection 2.4G (1KHz)/wired (1KHz)/Bluetooth (125Hz) ). In terms of specifications, series keyboards are optional

According to news from this website on March 31, Aitou recently launched an 87-key magnetic axis keyboard model "NA87MAG" on JD.com. The standard price is 219 yuan. If you pay a 10 yuan deposit, you will get an immediate discount of 20 yuan on the final payment. The actual price is 199 yuan. According to reports, this keyboard uses an Asat structure and is claimed to provide "HIFI-level typing sound quality and a consistent tough feel." Users can also adjust the feel of the keyboard by replacing different pads to achieve customization from tough to soft. Switching requirements. In addition, this keyboard is also equipped with a "three-dimensional game inner structure", which is said to be able to concentrate the sound of each key through a single-key closed design in a chessboard format, thereby "achieving three-dimensional sound optimization"; it also has 16.8 million colors of RGB light. Additionally, this keyboard features Le
