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>

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

本站8月12日消息,VGN于8月6日推出了联名《艾尔登法环》键鼠系列产品,包含键盘、鼠标和鼠标垫,采用菈妮/褪色者定制主题设计,目前系列产品已上架京东,售价99元起。本站附联名新品信息如下:VGN丨艾尔登法环S99PRO键盘该键盘采用纯铝合金外壳,辅以五层消音结构,使用GASKET板簧结构,拥有单键开槽PCB、原厂高度PBT材质键帽、铝合金个性化背板;支持三模连接和SMARTSPEEDX低延迟技术;接入VHUB,可一站式管理多款设备,首发549元。VGN丨艾尔登法环F1PROMAX无线鼠标该鼠标

华为手机如何实现双微信登录?随着社交媒体的兴起,微信已经成为人们日常生活中不可或缺的沟通工具之一。然而,许多人可能会遇到一个问题:在同一部手机上同时登录多个微信账号。对于华为手机用户来说,实现双微信登录并不困难,本文将介绍华为手机如何实现双微信登录的方法。首先,华为手机自带的EMUI系统提供了一个很便利的功能——应用双开。通过应用双开功能,用户可以在手机上同

微信键盘怎么设置皮肤?微信键盘是一款非常智能的手机输入法软件,这个软件上面有好多人性化的功能,它可以让用户自己选择输入模式,还可以在这个软件上面以最快的速度找到自己想要的表情然后发出去。这个软件上面还可以让用户自己更换键盘的皮肤,很多用户都还不太清楚要怎么更换皮肤,下面小编整理了皮肤的更换方式供大家参考。微信键盘皮肤的设置方法在手机的微信、短信或其他需要使用键盘的应用中,您可以点击键盘左上角的输入法设置图标,进入设置页面查看各种输入法的功能设置选项。 2、在输入法的设置页面点击“个性皮肤

本站2月29日消息,迈从今日为K87三模机械键盘推出了“风信子轴”“琉光冰淇淋轴”两款版本,该键盘主打“Gasket结构、80%配列”,相关轴体键盘价格信息如下:“风信子轴”版:首发价299元“琉光冰淇淋轴”版:首发价379元据介绍,系列键盘使用Gasket结构,采用87键80%配列,全键无冲,支持热插拔,号称选用“原厂/MDA双色PBT键帽”,使用1.2mm单键开槽PCB(下灯位),配备RGB灯效,并拥有磁吸收纳铭牌设计。此外,这款键盘配备6000毫安电池,无线延迟3ms,官方未公布键盘尺寸及

苹果手机键盘用户想要设置手写输入法,但是不知道怎么操作,其实是很简单的,用户可以在手机的键盘设置中直接选择手写输入法输入,如果没有也可以手动添加手写输入法。苹果手机键盘怎么设置手写输入法答:在键盘设置中直接启用手写输入法1、苹果用户在使用输入法的时候,默认是会开启手写输入法的。2、用户只需要在打字的时候直接点击左下角长按选择手写输入法就可以了。3、如果用户的手机里面没有手写输入法也可以进行手动的添加。4、用户进入设置找到通用键盘设置在第一个键盘里面添加手写输入的选项就可以了。5、使用手写输入法可

如何在华为手机上实现微信分身功能随着社交软件的普及和人们对隐私安全的日益重视,微信分身功能逐渐成为人们关注的焦点。微信分身功能可以帮助用户在同一台手机上同时登录多个微信账号,方便管理和使用。在华为手机上实现微信分身功能并不困难,只需要按照以下步骤操作即可。第一步:确保手机系统版本和微信版本符合要求首先,确保你的华为手机系统版本已更新到最新版本,以及微信App

本站7月19日消息,凌豹K87/PRO三模机械键盘将于今晚8点开售,两个版本不同之处主要在于轴体/配色/电池差异,其中标准版配备4000毫安时电池,PRO版本配备8000毫安时电池,本站整理价格信息如下:K87浅云白:99元K87凝夜紫/霞光紫/晴山蓝:149元K87微尘灰/星黛紫:199元K87PRO:249元据介绍,这款键盘采用Gasket结构,使用80%配列布局,可选多种色彩,内置下灯位RGB灯,支持三模连接2.4G(1KHz)/有线(1KHz)/蓝牙(125Hz)。规格方面,系列键盘可选

本站3月31日消息,艾石头近日在京东上架一款型号为“NA87MAG”的87键磁轴键盘,标准价格219元,支付10元定金尾款立减20元,实际到手199元。据介绍,这款键盘采用Asat结构,号称可提供“HIFI级别的打字音质和一致的硬朗手感”,用户也可以通过更换不同的垫片来调节键盘的手感,实现从硬朗到软弹的自定义切换需求。此外,这款键盘还配备“三维弈局内胆架构”,号称能够通过棋盘格式的单键位封闭设计集中每个键位的声音,从而“实现立体的声音优化”;同时拥有1680万色RGB灯光。此外,这款键盘采用Le
