最近在逛天猫,发现天猫的搜索框还不错,于是就决定动手实现一下这个界面,按照我的习惯首先是分析这个界面,然后构思实现的技术点,之后再动手写代码。

先上效果图:

swift searchtext多个热搜词滚动显示 swift搜索_加载

分析:

1:仔细看了看天猫的整体界面,我的想法是分为两个view,上面一个view装按钮、搜索框,下面一个view就是装一个可以滚动的ScrollView,看这种布局,所以ScrollView上面放一个CollectView(具有九宫格样式),好了,大致的控件摸清楚了,如何实现呢!不要急,一步步来

2:第一步分析整体界面,我用的xib布局整个界面,既然用到了xib,想要加载数据就得注册cell和定义Layout,而“猜你所想”和“最近搜索”是CollectView中的两个组头,所以想打好第一步,把该做的都搭好

//设置布局
       collectionView.setCollectionViewLayout(XYSearchLayout(), animated: true)
        
       //加载cell
       collectionView.registerNib(UINib(nibName: "XYSearchCell", bundle: nil), forCellWithReuseIdentifier: "XYSearchCell")

       //加载cell的头部
        collectionView.registerNib(UINib(nibName: "XYReusableView",  bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader , withReuseIdentifier:"XYReusableView")



3:它主要是分两组,第一组是一开始就加载”猜你所想“数据,当然这组数据应该是请求获取到的,而第二组数据是搜索时才会加载出来,也就是说只有用户进行搜索了才会显示第二组数据(当然用户搜索的也就成为了历史数据,存储下来),所以在搜索控件代理方法中获取到输入的内容然后直接添加到数组中,刷新

4:CollectView的布局利用系统的无法达到想要的效果,这里使用自定义布局。计算每个cell的位置

主要代码:


//这里就是返回每个cell,通过这里来调整位置
    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
       let arrCell =  super.layoutAttributesForElementsInRect(rect)
        for(var i = 1 ; i < arrCell?.count ; ++i){
            //当前 UICollectionViewLayoutAttributes
             let currentLayout = arrCell![i]
            //上一个 UICollectionViewLayoutAttributes
            let prevLayout = arrCell![i - 1]
            //前后两个cell属于同一个组的时候
            if (prevLayout.indexPath.section == currentLayout.indexPath.section) {
                //我们想设置的最大间距,可根据需要改
                let maximumSpacing = 15
                //前一个cell的最右边
                let origin = CGRectGetMaxX(prevLayout.frame);
                //如果当前一个cell的最右边加上我们想要的间距加上当前cell的宽度依然在contentSize中,我们改变当前cell的原点位置
                //不加这个判断的后果是,UICollectionView只显示一行,原因是下面所有cell的x值都被加到第一行最后一个元素的后面了
                if((CGFloat(origin) + CGFloat(maximumSpacing) + currentLayout.frame.size.width) < self.collectionViewContentSize().width) {
                    //就是两个cell之间的间距是maximumSpacing
                    var frame = currentLayout.frame
                    frame.origin.x = CGFloat(origin) + CGFloat(maximumSpacing)
                    currentLayout.frame = frame
                }
            }
        }
        return arrCell
   
    }

5:当然每个cell的大小也得计算,但是我们不能直接写死,因为每个cell的宽是根据文字的大小来合理设置的,所以这里我们又得实现返回每个item的Size代理方法。

代码:

//MARK - UICollectionViewDelegateFlowLayout  itme的大小  根据itme大小决定一行显示多少
    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
      
        let seacrhModel =  plistArr[indexPath.section] as? XYSearchModel
        if(seacrhModel?.content?.count > 0){
            
         let itemModel =  seacrhModel?.content![indexPath.row] as? XYItemModel
          //显示的内容
         let text = itemModel!.name! as NSString
         let size = text.boundingRectWithSize(CGSizeMake(CGFloat(MAXFLOAT), 24), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName:UIFont.systemFontOfSize(12)], context: nil).size
           return CGSizeMake(size.width+20, 24)
        }
        
        return CGSizeMake(80, 24)

    }



总结:主要的几个关键点差不多就是这些,其余的一些细节就得自己思考来写了,按照思路每一步慢慢实现,就能完成这个功能点。

代码地址