Swift: Complete a waterfall flow with Uicollectionview

Source: Internet
Author: User

本文的例子和Swift版本是基于Xcode7.2的。以后也许不知道什么时候会更新。
We're going to do something.

Use the open API of Sina Weibo to do the backend to realize the function we want to mention. Display the content, images and text of Sina Weibo in collection view. This article simply shows the content. The next article will show the same effect with Pinterest.

We are ready to show the pictures first. It's not easy for your friends to spend so much time taking pictures or choosing pictures from albums. If there is a medium-sized thumbnail in the data returned by the microblog, show the thumbnail for a long time. Otherwise, the text is displayed. The text is not the words ... This is not a micro-blog. But we will prepare a color to show it.

What is Uicollectionview?

Uicollectionview has a flexible layout that allows you to display data in a variety of different layouts.
The use of Uicollectionview is similar to that of UITableView, and it is also necessary to implement a set of DataSource agents and proxies for Uicollectionview itself to present the data in the interface.

UICollectionView也是UIScrollView的一个子类

The others are:
1. Uicollectionviewcell: These cells comprise the entire uicollectionview and are added to the Uicollectionview as a child view. Can be created in Interface Builder, or code can be created.
2. Header/footer: Concepts similar to UITableView. Displays some information about what the title is.

UICollectionView还有一个叫做Decoration view的东西。顾名思义,主要是装饰用的。不过要用这部分的功能你需要单独写定制的layout。

In addition to what has been said above, collection view has a special handling layout UICollectionViewLayout . You can inherit UICollectionViewLayout to create a layout of your own collection view. Apple gives a UICollectionViewFlowLayout basic layout that can be implemented in a fundamental flow layout. These will be described in a later tutorial.

Start our project:
Start by creating a single view app.

Then give your project a name, and here we call it CollectionViewDemo . The controller that is generated by default in storyboard is useful for wood. Kill directly, drag one UICollectionViewController in and set as the default controller. and delete the default generated viewcontroller.swift file, and create a file called Homecollectionviewcontroller.swift . Then, in Interface Builder, set the class for the collection view to HomeCollectionViewController .

And then:

    1. Add a navigation controller to the storyboard
    2. Set the collection view to the root view controller of the navigation controller above.
    3. Set this navigation controller to initial view controller.

Next, go back to Collection View controller again. This one

Learn more about Uicollectionview

As mentioned earlier, Uicollectionview and UITableView are similar and have DataSource and delegate. This allows you to set datasource and set some user interactions, such as when a cell is selected.

UICollectionViewFlowLayoutThere is a proxy: UICollectionViewDelegateFlowLayout . Through this agent can set some of the layout of the behavior such as: Cell spacing, Collection view scrolling direction and so on.

Let's start by filling in the UICollectionViewDataSource blanks with two proxies in our code UICollectionViewDelegateFlowLayout . The method is not for the time UICollectionViewDelegate being, will give the agent to fill in the blanks later.

Implement Uicollectionviewdatasource

Here we use the Weibo open API as an example. Get all of the current users ' tweets from the microblog development API, and then use Uicollectionview to show them. The available Weibo time line will be placed here at the end:

private var timelinestatus: [Statusmodel]?

The code in data source is good to add.

Mark:uicollectionviewdatasource    override func Numberofsectionsincollectionview (CollectionView: Uicollectionview), Int {        return 1    //1    }    override Func CollectionView (CollectionView: Uicollectionview, Numberofitemsinsection section:int), Int {        return self.timelinestatus?. Count?? 0//2    }    override Func CollectionView (Collectionview:uicollectionview, Cellforitematindexpath Indexpath: Nsindexpath), Uicollectionviewcell {let        cell = Collectionview.dequeuereusablecellwithreuseidentifier ( Reuseidentifier, Forindexpath:indexpath)        Cell.backgroundcolor = Uicolor.orangecolor ()//3        return cell    }
    1. We just need a section, so this returns the number 1.
    2. The returned time line will be placed in StatusModel an array of type. This array may be empty, because many situations can affect network requests, such as when the network is out of order. The time line returned at this point is empty. So self.timeLineStatus?.count the number may also be empty, then this time should return 0.
    3. Since there is no proper cell return, it is now time to see the cell layout in a way that changes the background color of the cell.

The effect is this:

Uicollectionviewflowlayoutdelegate

The role of this agent and UITableView func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat has a very similar effect. heightForRowAtIndexPaththe function is to return the height of the UITableViewCell. While Uicollectionviewcell has a very large number of different sizes, there is a need for more complex proxy method support. These include two methods:

1class Homecollectionviewcontroller:uicollectionviewcontroller, uicollectionviewdelegateflowlayout//2private Let sectioninsets = Uiedgeinsets (top:10.0, left:10.0, bottom:10.0, right:10.0)//Mark:uicollectionviewdelegateflowla yout//3func CollectionView (collectionview:uicollectionview, Layout collectionviewlayout:uicollectionviewlayout, Sizeforitematindexpath Indexpath:nsindexpath)-cgsize {    return cgsize (width:170, height:300)}//4func Collect Ionview (Collectionview:uicollectionview, Layout collectionviewlayout:uicollectionviewlayout, Insetforsectionatindex section:int), uiedgeinsets {    return sectioninsets}
    1. The first step is to implement the agent for layout UICollectionViewDelegateFlowLayout .
    2. Adds a property to sectionInsets the class.
    3. UICollectionViewDelegateFlowLayoutThe first method used to return the indexPath size of the cell at the specified location.
    4. Another way for the layout agent to return the inset of each section.

Look at the running effect:

Create a custom Uicollectionviewcell

The following is to deal with the content in the display when the specific how to show. We have two cases here, if the user's micro-blog has a picture, then the display of pictures. If you don't have a picture, display the text. Unfortunately the microblogging API does not return the size of the picture back. The size parameters are needed to determine this when displaying
UICollectionViewCellIn the end to how big size, because there is no need to get a block to show the picture. As for the image stretching method you have to decide, we here in order to simply use the default way to stretch the picture.

In the text you need to determine the size of the text according to how much. Because our width is certain, that is to say in the UILabel AutoLayout preferredMaxLayoutWidth is certain. Then it is convenient to calculate the height of multiple lines according to the width to UILabel show all the text in the microblog.

The first is the cell that displays the image.

Put one on the cell UIImageView to ensure that the four margins of this image view are all 0.

Create a file weiboimagecell.swift, the inside is the class WeiboImageCell , inherit from UICollectionViewCell .

Set the custom class of the cell to WeiboImageCell .

The image view in the cell code is then associated with the interface Builder's image view as Iboutelt:

Class Weiboimagecell:uicollectionviewcell {    @IBOutlet weak var weiboimageview:uiimageview!}

Repeat the above steps to add a single UILabel cell with a type of WeiboTextCell . Set this UILabel property numberOfLines to 0 so that you can display multiple lines of text. Then set the label's top, left, bottom, and right are-8.

为什么是-8呢,因为苹果默认的给父view留了宽度为8的margin(边距),如果要文字和Cell的边距贴合的话需要覆盖这个系统预留的边距,因此需要设置边距为-8。

The last associated code and label.

Class Weibotextcell:uicollectionviewcell {    @IBOutlet weak var weibotextlabel:uilabel!}

After adding these two cells, go back to HomeCollectionViewController . Delete self.collectionView!.registerClass(WeiboImageCell.self, forCellWithReuseIdentifier: reuseIdentifier) methods, and all of them registerClass .

`registerClass`, 这个方法的调用会把我们在storyboard里做的一切都给抹掉。在调用Cell里的image view或者label的时候得到的永远是nil。

Here, we need to discuss the text cell's constraint on label. First we also set the label constraint so that the label is attached to the side of the cell. That is, top, leading, trailing, and bottom are-8.

But this setting allows the label to be centered in the displayed cell. This is especially true when the text is not enough to fill the cell's space. So, we need to change a place. Modify the priority of the bottom, set to Low, lowest: UILayoutPriorityDefaultLow . This gives priority to the height of the text when the Labe is calculated, rather than setting the height of the Labe directly to the height of the cell as before. This time, whether or not the text fills the cell, it is starting from the top to show how much space the control is in.

Integrated Sdwebimage

What are we going to do to save the picture cell mess? Spicy is SDWebImage a library of well-known picture requests and caches. We use this library here to request images from Weibo and cache them.

Add to:
Pod SDWebImage application pod ' sdwebimage ', ' ~>3.7 ',added in Podfile. Of course we've added it before user_frameworks! . Why use this to read the original text:

to your project via frameworks instead of static libraries by specifying use_frameworks!. 

More will not say more, need to know more can see here.

After the pod update is complete. Introduce this framework.

Import Sdwebimage

You can then give the cell an image view slice.

WeiboImageCell.weiboImageView.sd_setImageWithURL (Nsurl (string:status.status). Bmiddlepic?? ""))

SDWebImagewrote a category for Image view. There are many methods that can be called. For example, you can set a place holder image. That is, you can set a default image for image view before the image is downloaded.

HTTP requests and data

Here are just a few simple things to look at here.
Let's look at what the open API of Weibo can give us back:

{"Statuses": [{"Created_at": "Tue May 17:46:55 +0800", "id": 11488058246, "Text": "Ask attention."            "," source ":" <a href= "http://weibo.com" rel= "nofollow" > Sina Weibo </a> "," favorited ": false, "Truncated": false, "in_reply_to_status_id": "", "in_reply_to_user_id": "", "in _reply_to_screen_name ":", "geo": null, "Mid": "5612814510546515491", "Reposts_count": 8                , "Comments_count": 9, "annotations": [], "user": {"id": 1404376560, "Screen_name": "Zaku", "name": "Zaku", "Province": "One", "City": " 5 "," Location ":" Chaoyang District, Beijing "," description ":" 50 years of life, is like a dream, the birth of the Dead, the heroes of what regrets. " "," url ":" Http://blog.sina.com.cn/zaku "," Profile_image_url ":" http://tp1.sinaimg.cn/140437 6560/50/0/1 "," DOmain ":" Zaku "," Gender ":" M "," Followers_count ": 1204, ...} }, ...], "ad": [{"id": 3366614911586452, "Mark": "AB21321XDFJJK"} , ...], "previous_cursor": 0,//temporarily does not support "Next_cursor": 11488013766,//temporarily does not support "Total_number": 8 1655}

We only need pictures or text of our follow friends ' tweets. So we can define the corresponding model class by these contents.

Import Objectmapperclass basemodel:mappable {    var previouscursor:int?    var nextcursor:int?    var hasvisible:bool?    var statuses: [Statusmodel]?    var totalnumber:int?    Required init? (_ Map:map) {    }    func Mapping (map:map) {        previouscursor <-map["Previous_cursor"]        nextcursor <-map["Next_ Cursor "]        hasvisible <-map[" hasvisible "]        statuses <-map[" statuses "]        totalnumber <-map[" Total_number "]    }}

And

Import Objectmapperclass Statusmodel:basemodel {    var statusid:string?    var thumbnailpic:string?    var bmiddlepic:string?    var originalpic:string?    var weibotext:string?    var user:wbusermodel?    Required init? (_ Map:map) {        super.init (map)    }    override Func mapping (map:map) {        super.mapping (map)        statusid <-map[" ID "]        thumbnailpic <-map[" Thumbnail_pic "]        bmiddlepic <-map[" Bmiddle_pic "]        originalpic <- map["Original_pic"]        weibotext <-map["text"]}    }

The contents of which are all placed in the class StatusModel , the picture we use Attributes bmiddlePic , text with weiboText . The other attributes are reserved for later use.

After the request is complete, these time line Weibo will have an attribute to use as the data source.

Class Homecollectionviewcontroller:uicollectionviewcontroller, uicollectionviewdelegateflowlayout {  private var timelinestatus: [Statusmodel]?  1  //2  alamofire.request (. GET, "Https://api.weibo.com/2/statuses/friends_timeline.json", Parameters:parameters, Encoding:. URL, Headers:nil)                . Responsestring (completionhandler: {response in let                    statuses = mapper<basemodel> (). Map (response.result.value)                    if let TimeLine = statuses where Timeline.totalnumber > 0 {                        self.timelinestatus = t Imeline.statuses//3                        Self.collectionview? Reloaddata ()                    }            )}
    1. The property that holds the data source.
    2. AlamofireMake an HTTP request.
    3. After the request succeeds, the data is parsed and the Weibo data we need is stored in the attribute self.timeLineStatus .

When displaying the data, it is necessary to distinguish whether the image of the microblog is present, or if the image is present, or the text is displayed.

A less good practice is to determine whether the data source exists in the method cell for collection view, and iterate through the item of each data source to see if the item has a picture ...

Override Func CollectionView (Collectionview:uicollectionview, Cellforitematindexpath Indexpath:nsindexpath) Uicollectionviewcell {  If let statuses = self.timelinestatus {let    status = Statuses[indexpath.item]    if Status   }}

This is obviously too lengthy, so we're going to lift this part of the code.

/**     Get status and if this status have image or not     @return:        status, one of the timeline        Int, 1:there ' s IM Age, 0:there's no image, -1:empty status     *    /func Getweibostatus (Indexpath:nsindexpath) (status:statusmod El, Hasimage:int) {  //1        if let timelinestatuslist = self.timelinestatus where Timelinestatuslist.count > 0 { Let            status = Timelinestatuslist[indexpath.item]            if let middlepic = status.bmiddlepic where middlepic! = "" {
   
    //there ' s middle sized image to show                return (status, 1)            } else {                //start to consider text                return (s Tatus, 0)            }        }        return (nil,-1)    }
   

Swift is capable of returning multiple values in a single method. The value of this multiple content is used tuple to store. This is called when:

Let status = Self.getweibostatus (Indexpath) Let Hasimage = status?. Hasimage              //If there ' s a image let ImageUrl = Status.status?. Bmiddlepic     //image Pathlet Text = Status.status?. Weibotext          //text

let hasImage = status?.hasImageyou can tell if there is a picture if you pass it. So this is very handy for swift. Then it is very convenient to judge which cell to display. The revised code is also very concise. This habit needs to keep going.

Override Func CollectionView (Collectionview:uicollectionview, Cellforitematindexpath Indexpath:nsindexpath) Uicollectionviewcell {Let status = Self.getweibostatus (Indexpath) var Cell:uicollectionviewcell = Uicollec            Tionviewcell () guard Let _ = Status.status else {cell.backgroundcolor = Uicolor.darktextcolor () Return cell} if Status.hasimage = = 1 {cell = Collectionview.dequeuereusablecellwithreuseide Ntifier (Reuseidentifier, forindexpath:indexpath) Let Weiboimagecell = Cell as! Weiboimagecell WeiboImageCell.weiboImageView.backgroundColor = Uicolor.bluecolor () weiboimagecell.we Iboimageview.sd_setimagewithurl (Nsurl (string:status.status). Bmiddlepic?? ")})} else if Status.hasimage = = 0 {cell = Collectionview.dequeuereusablecellwithreuseidentifier (reuse Textidentifier, forindexpath:indexpath) Let Weibotextcell = Cell as! Weibotextcell weIbotextcell.setcellwidth (self.cellwidth) WeiboTextCell.weiboTextLabel.text = Status.status?. Weibotext?? "" WeiboTextCell.contentView.backgroundColor = Uicolor.orangecolor () weiboTextCell.weiboTextLabel.ba Ckgroundcolor = Uicolor.redcolor ()} else {cell = Uicollectionviewcell ()} Cell.backgroun Dcolor = Uicolor.orangecolor ()//3 return cell}

Run up and look at the running effect.

So ugly!!!

All the code here.

To be Continued

Swift: Complete a waterfall flow with Uicollectionview

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.