對于電商App來說,首頁一般都是一個多個內(nèi)容聚合的頁面旭蠕。整體是列表但是里面內(nèi)容特別雜停团。所以寫代碼的時候就要考慮邏輯要清晰旷坦,還要對類型的擴(kuò)展要容易。
下面根據(jù)我18年寫的一個代碼說下這個事(主要是需求更新這部分代碼沒用了佑稠,去掉前留個紀(jì)念)秒梅。
說一下這個需求,因?yàn)闀r間有點(diǎn)長記得不是很清楚了舌胶,就大致說下番电,頭試圖,cell辆琅,尾視圖都有多種樣式漱办。根據(jù)相鄰兩個cell的樣式不同間距也可能不同。
實(shí)現(xiàn)方案
整體結(jié)構(gòu):
頁面整體就是一個collectionView婉烟,每一條后端數(shù)據(jù)都對應(yīng)一個section娩井,這樣做的目的:1每一條數(shù)據(jù)都可能攜帶頭部信息和尾部信息(不攜帶頭部尾部時可以拼接在一起),2可能存在有二維數(shù)據(jù)的情況
2:二維的數(shù)據(jù):
代碼實(shí)現(xiàn)
然后就是collectionView的代碼的寫法問題了似袁。整體來看大的結(jié)構(gòu)就是抽象工廠加策略
一洞辣,我寫了一個管理類通過管理類現(xiàn)實(shí)cell的代理,把動態(tài)樓層(下面我們就這么叫吧)相關(guān)的邏輯拿了出來昙衅。只放了部分代碼主要講解思路扬霜。
調(diào)用部分
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
//動態(tài)模塊section下的item
KFZShopHomeCardsModel * cards = [_dataModel.cardsModel.localCardsList objectAtIndexCheck:section];
return [KFZMainPageModuleCreater moduleItemCountWithModel:cards];
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
//動態(tài)模塊創(chuàng)建
KFZShopHomeCardsModel * cards = [_dataModel.cardsModel.localCardsList objectAtIndexCheck:indexPath.section];
return [KFZMainPageModuleCreater createCellWithModel:cards CollectionView:collectionView IndexPath:indexPath];
}
工具類內(nèi)部
@interface KFZDynamicModuleCellCeater : NSObject
//----cell
+(UICollectionViewCell *)createCellWithModel:(KFZShopHomeCardsModel *)moduleModel CollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath;
+(NSInteger)moduleItemCountWithModel:(KFZShopHomeCardsModel *)moduleModel;
+(void)moduleItemClickWithModel:(KFZShopHomeCardsModel *)moduleModel IndexPath:(NSIndexPath *)indexPath;
+(CGSize)moduleItemSizeWithModel:(KFZShopHomeCardsModel *)moduleModel IndexPath:(NSIndexPath *)indexPath;
//----headerView
+(UICollectionReusableView *)createHeaderViewWithModel:(KFZShopHomeCardsModel *)moduleModel CollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath;
+(CGSize)moduleIHeaderSizeWithModel:(KFZShopHomeCardsModel *)moduleModel;
+(UICollectionReusableView *)defautCollectionReusableViewCollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath;
//----footerView
+(UICollectionReusableView *)createFooterViewWithModel:(KFZShopHomeCardsModel *)moduleModel CollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath;
+(CGSize)moduleIFooterSizeWithModel:(KFZShopHomeCardsModel *)moduleModel;
+(UICollectionReusableView *)defautCollectionFooterViewCollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath;
+(CGFloat)sameModuleSpaceHeight:(CardsType)cardType;
//----sectionLayout section各種間距
+(UIEdgeInsets)sectionInsetsWithModel:(KFZShopHomeCardsModel *)moduleModel;
+(CGFloat)sectionLineSpacingWithModel:(KFZShopHomeCardsModel *)moduleModel;
+(CGFloat)sectionItemSpacingWithModel:(KFZShopHomeCardsModel *)moduleModel;
//---regist
+(void)registAllClassIdentifirsCollectionView:(UICollectionView *)collectView;
@end
@implementation KFZDynamicModuleCellCeater
#pragma mark - 模塊下 Cell
/**
根據(jù) 模塊的類型 創(chuàng)建cell
@param moduleModel 模塊數(shù)據(jù)
@param collectionView 當(dāng)前的collectionView
@param indexPath 當(dāng)前indexPath
@return 創(chuàng)建的cell
*/
+(UICollectionViewCell *)createCellWithModel:(KFZShopHomeCardsModel *)moduleModel CollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath{
return [[KFZDynamicModuleConfig factoryConfig:moduleModel.winddowShowType] createCellWithModel:moduleModel CollectionView:collectionView IndexPath:indexPath];
}
/**
item的size
@param moduleModel 數(shù)據(jù)
@param indexPath 位置
@return 計(jì)算出的size
*/
+(CGSize)moduleItemSizeWithModel:(KFZShopHomeCardsModel *)moduleModel IndexPath:(NSIndexPath *)indexPath{
return [[KFZDynamicModuleConfig factoryConfig:moduleModel.winddowShowType] moduleItemSizeWithModel:moduleModel IndexPath:indexPath];
}
/**
item點(diǎn)擊方法
*/
+(void)moduleItemClickWithModel:(KFZShopHomeCardsModel *)moduleModel IndexPath:(NSIndexPath *)indexPath{
[[KFZDynamicModuleConfig factoryConfig:moduleModel.winddowShowType] moduleItemClickWithModel:moduleModel IndexPath:indexPath];
}
/**
每個模塊item的個數(shù)
*/
+(NSInteger)moduleItemCountWithModel:(KFZShopHomeCardsModel *)moduleModel{
return [[KFZDynamicModuleConfig factoryConfig:moduleModel.winddowShowType]moduleItemCountWithModel:moduleModel];
}
#pragma mark - 模塊中的各種間距
+(UIEdgeInsets)sectionInsetsWithModel:(KFZShopHomeCardsModel *)moduleModel{
return [[KFZDynamicModuleConfig factoryConfig:moduleModel.winddowShowType]sectionInsetsWithModel:moduleModel];
}
+(CGFloat)sectionLineSpacingWithModel:(KFZShopHomeCardsModel *)moduleModel{
return [[KFZDynamicModuleConfig factoryConfig:moduleModel.winddowShowType]sectionLineSpacingWithModel:moduleModel];
}
+(CGFloat)sectionItemSpacingWithModel:(KFZShopHomeCardsModel *)moduleModel{
return [[KFZDynamicModuleConfig factoryConfig:moduleModel.winddowShowType]sectionItemSpacingWithModel:moduleModel];
}
#pragma mark - 模塊下 頭試圖
+(UICollectionReusableView *)createHeaderViewWithModel:(KFZShopHomeCardsModel *)moduleModel CollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath{
return [[KFZDynamicModuleConfig headerFactoryConfigWithHeaderStr:moduleModel.sectionHeaderStyleName]createHeaderViewWithModel:moduleModel CollectionView:collectionView IndexPath:indexPath];
}
+(CGSize)moduleIHeaderSizeWithModel:(KFZShopHomeCardsModel *)moduleModel{
return [[KFZDynamicModuleConfig headerFactoryConfigWithHeaderStr:moduleModel.sectionHeaderStyleName]moduleIHeaderSizeWithModel:moduleModel];
}
/**
默認(rèn)透明頭試圖
*/
+(UICollectionReusableView *)defautCollectionReusableViewCollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath{
UICollectionReusableView * headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass([UICollectionReusableView class]) forIndexPath:indexPath];
headerView.backgroundColor = [UIColor clearColor];
return headerView;
}
#pragma mark - 模塊下 尾視圖 *** 模塊之前的間隔 由這里控制
+(UICollectionReusableView *)createFooterViewWithModel:(KFZShopHomeCardsModel *)moduleModel CollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath{
if (moduleModel.isHaveFooter) {
KFZShopHomeAreaFooterView * footer = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:NSStringFromClass([KFZShopHomeAreaFooterView class]) forIndexPath:indexPath];
if ([moduleModel.showMoreType isEqualToString:@"1"]) {
footer.footerType = KFZShopHomeFooterType_LookMore;
}else{
footer.footerType = KFZShopHomeFooterType_FreshList;
}
footer.sectionIndex = indexPath.section;
footer.sectionModel = moduleModel;
__weak typeof(collectionView)wkCollection = collectionView;
footer.selfBeClick = ^(NSInteger section) {
[wkCollection reloadSections:[NSIndexSet indexSetWithIndex:section]];
};
return footer;
}
return [self defautCollectionFooterViewCollectionView:collectionView IndexPath:indexPath];
}
+(CGSize)moduleIFooterSizeWithModel:(KFZShopHomeCardsModel *)moduleModel{
if (moduleModel.isHaveFooter) {
KFZShopHomeCardsModel * nextModel = moduleModel.nextLink;
if (nil != nextModel && (nextModel.HaveHeaderTitle || nextModel.HaveHeaderScran)) {
return CGSizeMake(DEF_SCREEN_WIDTH, 70 + 10);
}
return CGSizeMake(DEF_SCREEN_WIDTH, 70);
}else{
KFZShopHomeCardsModel * nextModel = moduleModel.nextLink;
//要判斷兩個模塊之間的距離 所以取值上保證不是最后一個模塊
if (nil != nextModel) {
//如果下一個模塊有頭試圖的話 算是兩個模塊了 當(dāng)前模塊向下的間隔應(yīng)該是47
if (nextModel.HaveHeaderTitle || nextModel.HaveHeaderScran || nextModel.HaveHeaderLabels) {
return CGSizeMake(DEF_SCREEN_WIDTH, 47);
}
//如果沒有頭試圖的時候
//判斷兩個模塊是否是一種類型
if (moduleModel.winddowShowType == nextModel.winddowShowType) {
return CGSizeMake(DEF_SCREEN_WIDTH, [self sameModuleSpaceHeight:moduleModel.winddowShowType]);
}
//兩種模塊不是一種類型
//兩種模塊不是一種類型 但是兩種模塊分別是兩格(twoCard)和三格(threeCard)
if ((moduleModel.winddowShowType == CardsType_twoCard || moduleModel.winddowShowType == CardsType_threeCard) && (nextModel.winddowShowType == CardsType_twoCard || nextModel.winddowShowType == CardsType_threeCard)) {
return CGSizeMake(DEF_SCREEN_WIDTH, 3);
}
//兩種模塊不是一種類型 但是兩種模塊分別是一個高(OneCard_height)和一格矮(OneCard)
else if ((moduleModel.winddowShowType == CardsType_OneCard_height || moduleModel.winddowShowType == CardsType_OneCard) && (nextModel.winddowShowType == CardsType_OneCard_height || nextModel.winddowShowType == CardsType_OneCard)) {
return CGSizeMake(DEF_SCREEN_WIDTH, 3);
}
else{
return CGSizeMake(DEF_SCREEN_WIDTH, 47);
}
}
//最后一個模塊的邏輯
//如果是猜你喜歡 下面會有一個查看更多的尾試圖所以要把間距改為0
if (moduleModel.winddowShowType == CardsType_GuessYouLike) {
return CGSizeMake(DEF_SCREEN_WIDTH, 0);;
}
}
return CGSizeMake(DEF_SCREEN_WIDTH, 0);
}
/**
默認(rèn)透明尾試圖
*/
+(UICollectionReusableView *)defautCollectionFooterViewCollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath{
UICollectionReusableView * headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:NSStringFromClass([UICollectionReusableView class]) forIndexPath:indexPath];
headerView.backgroundColor = [UIColor clearColor];
return headerView;
}
/**
上下兩個是同類型時的間距
*/
+(CGFloat)sameModuleSpaceHeight:(CardsType)cardType{
switch (cardType) {
case CardsType_OneCard_height:{
return 3;
}
case CardsType_OneCard:{
return 3;
}
case CardsType_twoCard:{
return 3;
}
case CardsType_threeCard:{
return 3;
}
case CardsType_preciousBook:{
return 25;
}
case CardsType_goodBook:{
return 25;
}
case CardsType_goodShop:{
return 15;
}
case CardsType_GuessYouLike:{
return 10;
}
case CardsType_BookList:{
return 47;
}
default:
return 47;
}
}
#pragma mark - 注冊方法
/**
像當(dāng)前的collectionView注冊cell和頭尾試圖 --- (一點(diǎn)不好 所有的都要注冊現(xiàn)有的全部類型)
@param collectView 當(dāng)前的collectionView
*/
+(void)registAllClassIdentifirsCollectionView:(UICollectionView *)collectView{
[collectView registerClass:[KFZShopThreeCardCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZShopThreeCardCell class])];
[collectView registerClass:[KFZShopTwoCardCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZShopTwoCardCell class])];
[collectView registerClass:[KFZOneHeightCardCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZOneHeightCardCell class])];
[collectView registerClass:[KFZOneLowCardCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZOneLowCardCell class])];
[collectView registerClass:[KFZImageTitlePrise_GoodsCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZImageTitlePrise_GoodsCell class])];
[collectView registerClass:[KFZImageTitleAuthorPrise_GoodsCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZImageTitleAuthorPrise_GoodsCell class])];
[collectView registerClass:[KFZShopHomeAreaShopCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZShopHomeAreaShopCell class])];
[collectView registerClass:[KFZGuessYourLikeCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZGuessYourLikeCell class])];
[collectView registerClass:[KFZChannelBoolListCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZChannelBoolListCell class])];
[collectView registerClass:[KFZISBNHorizontalScrollCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZISBNHorizontalScrollCell class])];
[collectView registerClass:[KFZISBNTableStyleCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZISBNTableStyleCell class])];
[collectView registerClass:[KFZGoodsHorizontalScrollCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZGoodsHorizontalScrollCell class])];
[collectView registerClass:[KFZAuctionHorizontalScrollCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZAuctionHorizontalScrollCell class])];
[collectView registerClass:[KFZGoodsTableStyleCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZGoodsTableStyleCell class])];
[collectView registerClass:[KFZAuctionSpecialHorizontalScrollCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZAuctionSpecialHorizontalScrollCell class])];
[collectView registerClass:[KFZAuctionAdvertisementCell class] forCellWithReuseIdentifier:NSStringFromClass([KFZAuctionAdvertisementCell class])];
[collectView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:NSStringFromClass([UICollectionReusableView class])];
[collectView registerClass:[KFZShopHomeAreaFooterView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:NSStringFromClass([KFZShopHomeAreaFooterView class])];
[collectView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass([UICollectionReusableView class])];
[collectView registerClass:[KFZOnlyTitleHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass([KFZOnlyTitleHeaderView class])];
[collectView registerClass:[KFZOnlyScreenHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass([KFZOnlyScreenHeaderView class])];
[collectView registerClass:[KFZTitleAndScreenHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass([KFZTitleAndScreenHeaderView class])];
[collectView registerClass:[KFZOnlyLabelsHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass([KFZOnlyLabelsHeaderView class])];
[collectView registerClass:[KFZTitleAndLabelsHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass([KFZTitleAndLabelsHeaderView class])];
}
@end
二,可以看到上面代碼KFZDynamicModuleConfig這個算是一個策略選擇不過我內(nèi)部是用映射是生成對應(yīng)的工廠的而涉。(正常寫的話肯定是先寫出工廠然后才有這個著瓶,不過看代碼正好是可以按照這個關(guān)聯(lián)性去看)
@interface KFZDynamicModuleConfig : NSObject
/**
根據(jù) 模塊類型枚舉的值 來取工廠類
@return 返回對應(yīng)的工廠類
*/
+(KFZDynamicModuleCellFactory *)factoryConfig:(CardsType)type;
/**
根據(jù) 模塊類型枚舉的值 來取工廠類
@return 返回對應(yīng)的工廠類
*/
+(KFZDynamicModuleHeaderFactory *)headerFactoryConfig:(CardsHeadType)type;
/**
根據(jù) 頭試圖描述字符串 來取工廠類
@return 返回對應(yīng)的工廠類
*/
+(KFZDynamicModuleHeaderFactory *)headerFactoryConfigWithHeaderStr:(NSString *)headerStr;
/** 通知-通知頻道頁面刷新(ps:主要做換一換功能只是在當(dāng)前頁面的一個通知,頁面不顯示就移除) */
FOUNDATION_EXPORT NSString *const ChannelController_FreshSection;
@end
···
···
#import "KFZDynamicModuleConfig.h"
@implementation KFZDynamicModuleConfig
+(KFZDynamicModuleCellFactory *)factoryConfig:(CardsType)type{
NSArray * list = @[@"KFZOneCardHeightFactory"
,@"KFZOneCardLowFactory"
,@"KFZTwoCardFactory"
,@"KFZThreeCardFactory"
,@"KFZVerticalBookFactory"
,@"KFZVerticalISBNFactory"
,@"KFZVerticalShopFactory"
,@"KFZGuessYouLikeGoodsFactory"
,@"KFZHorizontalBookListFactory"
,@"KFZISBNHorizontalScrollFactory"
,@"KFZISBNTableStyleFactory"
,@"KFZGoodsHorizontalScrollFactory"
,@"KFZAuctionHorizontalScrollFactory"
,@"KFZGoodsTableStyleFactory"
,@"KFZAuctionSpecialHorizontalScrollFactory"
,@"KFZAuctionAdvertisementFactory"];
NSString * className = list[type];
Class class = NSClassFromString(className);
KFZDynamicModuleCellFactory * factory = [class new];
return factory;
}
+(KFZDynamicModuleHeaderFactory *)headerFactoryConfig:(CardsHeadType)type{
NSArray * list = @[@"KFZPureColor_WhiteHeaderFactory"
,@"KFZOnlyTitleHeaderFactory"
,@"KFZOnlyScreenHeaderFactory"
,@"KFZTitleAndScreenHeaderFactory"
,@"KFZOnlyLabelsHeaderFactory"
,@"KFZTitleAndLabelsHeaderFactory"];
NSString * className = list[type];
Class class = NSClassFromString(className);
KFZDynamicModuleHeaderFactory * factory = [class new];
return factory;
}
+(KFZDynamicModuleHeaderFactory *)headerFactoryConfigWithHeaderStr:(NSString *)headerStr{
NSDictionary * list = @{@"haveTitlehaveScranhaveLabels":@"KFZTitleAndScreenHeaderFactory",//=
@"haveTitlehaveScrannoLabels":@"KFZTitleAndScreenHeaderFactory",
@"haveTitlenoScranhaveLabels":@"KFZTitleAndLabelsHeaderFactory",
@"haveTitlenoScrannoLabels":@"KFZOnlyTitleHeaderFactory",
@"noTitlehaveScranhaveLabels":@"KFZOnlyScreenHeaderFactory",//=
@"noTitlehaveScrannoLabels":@"KFZOnlyScreenHeaderFactory",
@"noTitlenoScranhaveLabels":@"KFZOnlyLabelsHeaderFactory",
@"noTitlenoScrannoLabels":@"KFZPureColor_WhiteHeaderFactory",
};
NSString * className = list[headerStr];
Class class = NSClassFromString(className);
KFZDynamicModuleHeaderFactory * factory = [class new];
return factory;
}
NSString *const ChannelController_FreshSection = @"com.Kongfz.ChannelController_FreshSection";//通知-通知頻道頁面刷新
@end
這里面的一些枚舉啼县,其實(shí)就是后端標(biāo)識的數(shù)據(jù)類型材原,我這面轉(zhuǎn)成枚舉了。
第三季眷,就是多個工廠的實(shí)現(xiàn)了余蟹。在KFZDynamicModuleConfig可以看見我返回工廠時的類是KFZDynamicModuleCellFactory這里我是使用基類的方式代替了協(xié)議了。
這里我就舉個簡單的例子吧子刮,就上面一橫行兩個圖片的那種威酒。
@interface KFZTwoCardFactory : KFZDynamicModuleCellFactory
@end
@implementation KFZTwoCardFactory
//----cell
-(UICollectionViewCell *)createCellWithModel:(KFZShopHomeCardsModel *)moduleModel CollectionView:(UICollectionView *)collectionView IndexPath:(NSIndexPath *)indexPath{
KFZShopTwoCardCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([KFZShopTwoCardCell class]) forIndexPath:indexPath];
cell.model = moduleModel;
return cell;
}
-(NSInteger)moduleItemCountWithModel:(KFZShopHomeCardsModel *)moduleModel{
return 1;
}
-(void)moduleItemClickWithModel:(KFZShopHomeCardsModel *)moduleModel IndexPath:(NSIndexPath *)indexPath{
//cellb內(nèi)部做跳轉(zhuǎn)了
}
-(CGSize)moduleItemSizeWithModel:(KFZShopHomeCardsModel *)moduleModel IndexPath:(NSIndexPath *)indexPath{
return CGSizeMake(DEF_SCREEN_WIDTH - 30, 66*SHOPHOMEAREA_WIDTH_RATIO);
}
//----sectionLayout section各種間距
-(UIEdgeInsets)sectionInsetsWithModel:(KFZShopHomeCardsModel *)moduleModel{
return UIEdgeInsetsMake(0, 15, 0, 15);
}
-(CGFloat)sectionLineSpacingWithModel:(KFZShopHomeCardsModel *)moduleModel{
return 25;
}
-(CGFloat)sectionItemSpacingWithModel:(KFZShopHomeCardsModel *)moduleModel{
return 15*SHOPHOMEAREA_WIDTH_RATIO;
}
@end
整體結(jié)構(gòu)就這樣說完了,其實(shí)也不是很復(fù)雜是不是挺峡。最后附加一個我這里類型的截圖:
打完收工!!!