iOS -創(chuàng)建一個(gè)商品排序?qū)Ш綑?/h1>

背景

結(jié)合上一個(gè)篩選框豆赏,寫一個(gè)商品的排序?qū)Ш礁茉啊?shí)現(xiàn)特定種類商品的綜合、銷量筒狠,價(jià)格排序猪狈。

演示.gif

創(chuàng)建視圖

把每一個(gè)選項(xiàng)卡做成自定義的視圖ScreenNavBarItem,給這個(gè)view三種狀態(tài):未選中辩恼,單次選中雇庙,雙次選中(選中狀態(tài)下有升序和降序兩種)。

/**
 item的樣式

 - ItemSelelctTypeNone: 未選中
 - ItemSelelctTypeSingleType: 單擊
 - ItemSelelctTypeDoubleType: 雙擊
 */
typedef NS_ENUM(NSInteger,ItemSelelctType) {
    ItemSelelctTypeNone = 0,
    ItemSelelctTypeSingleType = 1,
    ItemSelelctTypeDoubleType = 2        
};

不同的狀態(tài)他們都有不同的樣式灶伊。比如title的文案變色還有圖片更改疆前。這部分的處理交給數(shù)據(jù)模型。

好處有:

  • 可以通過創(chuàng)建符合約定的model聘萨,就能創(chuàng)建任意多的item竹椒。
  • 如果item需要更改樣式的話,我們只需要改變model然后刷新就好了米辐。

其中的itemCode用來做這個(gè)item唯一標(biāo)識(shí)碾牌,方便后面的點(diǎn)擊事件的邏輯處理。

@interface ScreenNavDataModel : NSObject

@property(nonatomic, copy) NSString *title;

@property(nonatomic, copy) NSString *normalImage;

@property(nonatomic, copy) NSString *selectSingleImage;

@property(nonatomic, copy) NSString *selectDoubleImage;

@property(nonatomic, assign) NSInteger itemCode;

@property(nonatomic, assign) ItemSelelctType type;

@end

然后添加item的初始化方法和外部刷新方法儡循。

/**
 初始化方法

 @param model 數(shù)據(jù)源
 @return 實(shí)例
 */
- (instancetype)initWithItemModel:(ScreenNavDataModel *)model;


/**
 更新item的樣式

 @param type 樣式的枚舉
 */
- (void)updateWithType:(ItemSelelctType)type;

然后將這些按鈕組裝起來舶吗,放入一個(gè)view(AllProductScreenNavBar)內(nèi)。由于item的個(gè)數(shù)不固定择膝,所以要做好寬度的適配誓琼。同樣它也需要一個(gè)初始化和刷新的方法。

#import <UIKit/UIKit.h>
#import "ScreenNavDataModel.h"
#import "ScreenNavBarItem.h"


typedef void(^itemSelect)(ScreenNavBarItem *item, NSInteger selectIndex);

@interface AllProductScreenNavBar : UIView

@property(nonatomic, copy) itemSelect itemSelect;


/**
 初始化

 @param dataArray item數(shù)據(jù)源
 @return 實(shí)例
 */
- (instancetype)initWithScreenNavData:(NSArray<ScreenNavDataModel *> *) dataArray;

/**
 更新視圖

 @param dataModel 更新選中方案的數(shù)組
 */
- (void)updateWithScreenNavData:(NSArray<ScreenNavDataModel *> *)dataModel;

@end

接下來是要思考處理頁面的交互了肴捉。

頁面交互

在AllProductScreenNavBar中腹侣,我們定義了一個(gè)block來傳遞事件。參數(shù)item是為了能夠拿到item的code標(biāo)識(shí)齿穗。通過給item添加手勢(shì)傲隶,點(diǎn)擊后回觸發(fā)這個(gè)block。我們通過計(jì)算的方式拿到點(diǎn)擊的index窃页。

- (void)userSelectIndexItem:(UITapGestureRecognizer *)tap {
    if (self.itemSelect) {
        //找到點(diǎn)擊的item跺株,并將其他item的選中狀態(tài)置空
        CGFloat centerX = CGRectGetMidX(tap.view.frame);
        NSInteger selectIndex = 0;
        for (int i = 0; i < self.itemArray.count; i ++) {
            CGFloat minX = i*self.unitWidth;
            CGFloat maxX = (1+i)*self.unitWidth;
            if (centerX > minX  && centerX < maxX ) {
                selectIndex = i;
            }
        }
        
        ScreenNavBarItem *item = self.itemArray[selectIndex];
//        ScreenNavBarItem *item = (ScreenNavBarItem *)tap.view;
        self.itemSelect(item,selectIndex);
    }
}

其實(shí)我們可以只把item block出去复濒,然后controller里面遍歷一下,如果block出去的item == listModel里面的某一個(gè)就可以拿到這個(gè)index乒省∏删保或者直接定義itemCode 就是當(dāng)前item的下標(biāo)也可以。

在ViewController中我們初始化一個(gè)AllProductScreenNavBar的實(shí)例袖扛,并寫一下他的事件處理砸泛。

_bar = [[AllProductScreenNavBar alloc] initWithScreenNavData:_listModel.list];
   
   __weak typeof(self) weakSelf = self;
   _bar.itemSelect = ^(ScreenNavBarItem *item, NSInteger selectIndex) {
       //更改item的點(diǎn)擊類型
       //點(diǎn)擊行(無>單擊,點(diǎn)擊>雙擊蛆封,雙擊>單擊)
       //非點(diǎn)擊行 任意狀態(tài)>無
       [weakSelf.listModel handleItemModelArrayWithItemSelect:selectIndex];
       
       //根據(jù)點(diǎn)擊狀態(tài)和code得到排序類型
       item.currentType = weakSelf.listModel.list[selectIndex].type;
       ProductSortType type = [weakSelf currentItemState:item.currentItemCode itemCurrentType:item.currentType];
       
       //處理事件
       [weakSelf eventWithSortType:type];
       [weakSelf updateData];
   };

因?yàn)楹Y選和其他的排序是可以共存的唇礁,所以要在篩選框的代理方法中處理一下這種特殊情況。主要是篩選框的點(diǎn)擊狀態(tài)這塊需要和其他的item分開惨篱。有一點(diǎn)需要注意垒迂,如果這個(gè)狀態(tài)沒有更改就不用刷新。比如重復(fù)點(diǎn)開篩選框關(guān)閉篩選框操作妒蛇,這個(gè)時(shí)候狀態(tài)就不必更改

- (void)alertViewDidSelectSureButtonWithId:(NSString *)tagId {
    if (tagId.length) {
        _tagId = tagId;
        //傳回來的ID
        ScreenNavDataModel *model4 = _listModel.list[3];
        if (model4.type != ItemSelelctTypeSingleType) {
            model4.type = ItemSelelctTypeSingleType;
            [self updateData];
        }
        _StatusLabel.text = [NSString stringWithFormat:@"%@+tagId=%@",[_StatusLabel.text substringToIndex:4],_tagId];
    }
    
}

- (void)alertViewDidSelectResetButtonClick {
    _tagId = @"";
    _lastScreenModel = nil;
    ScreenNavDataModel *model4 = _listModel.list[3];
    if (model4.type != ItemSelelctTypeNone) {
        model4.type = ItemSelelctTypeNone;
        _StatusLabel.text = [NSString stringWithFormat:@"%@+tagId被重置",[_StatusLabel.text substringToIndex:4]];
        [self updateData];
    }
    
}

反思

當(dāng)初這塊的代碼是走一步看一步寫的沒有思考那么多机断,很多地方都沒有考慮周到,散發(fā)出一種壞味道绣夺。從項(xiàng)目中抽離出來后吏奸,給重構(gòu)了一遍。 本來判斷的排序類型是放在ScreenNavBarItem的陶耍,然后通過硬編碼的方式根據(jù)每個(gè)model的title來區(qū)分不同的類型在block出去奋蔚,這樣很不友好,不利于復(fù)用烈钞。如果需要一個(gè)新的排序的話泊碑,還得修改這個(gè)item.

- (ProductSortType)currentItemState {
    if ([_title isEqualToString:@"綜合"]) {
        return ProductSortTypeComprehensive;
    }
    if ([_title isEqualToString:@"銷量"]) {
        return ProductSortTypeSalesDesc;
    }
    if ([_title isEqualToString:@"價(jià)格"]) {
        if (_currentType == ItemSelelctTypeSingleType) {
            return ProductSortTypePriceAsc;
        } else if (_currentType == ItemSelelctTypeDoubleType) {
            return ProductSortTypePriceDesc;
        }
    }
    if ([_title isEqualToString:@"篩選"]) {
        return ProductSortTypeScreening;
    }
    return 0;
}

還有數(shù)據(jù)處理部分放在了listModel里面,借用了
- (NSString *)substringToIndex:(NSUInteger)to;
這種方式來返回一個(gè)新的listModel毯欣。以前是在controller里面處理馒过。

代碼

https://github.com/bumingxialuo/NavTool
如果本文中的方法或者思路對(duì)你有些幫助,點(diǎn)個(gè)star哦酗钞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者

  • 序言:七十年代末腹忽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子砚作,更是在濱河造成了極大的恐慌窘奏,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件葫录,死亡現(xiàn)場(chǎng)離奇詭異着裹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)米同,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門骇扇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摔竿,“玉大人,你說我怎么就攤上這事匠题≌兀” “怎么了但金?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵韭山,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我冷溃,道長(zhǎng)钱磅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任似枕,我火速辦了婚禮盖淡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凿歼。我一直安慰自己褪迟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布答憔。 她就那樣靜靜地躺著味赃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪虐拓。 梳的紋絲不亂的頭發(fā)上心俗,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音蓉驹,去河邊找鬼城榛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛态兴,可吹牛的內(nèi)容都是我干的狠持。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瞻润,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼工坊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起敢订,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤王污,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后楚午,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昭齐,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年矾柜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阱驾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片就谜。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖里覆,靈堂內(nèi)的尸體忽然破棺而出丧荐,到底是詐尸還是另有隱情,我是刑警寧澤喧枷,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布虹统,位于F島的核電站,受9級(jí)特大地震影響隧甚,放射性物質(zhì)發(fā)生泄漏车荔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一戚扳、第九天 我趴在偏房一處隱蔽的房頂上張望忧便。 院中可真熱鬧,春花似錦帽借、人聲如沸珠增。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒂教。三九已至,卻和暖如春辐董,著一層夾襖步出監(jiān)牢的瞬間悴品,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工简烘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留苔严,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓孤澎,卻偏偏與公主長(zhǎng)得像届氢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子覆旭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355