Hi I wanted to achieve the below design using swift .Please find image below for reference.
.
The only way I can think about do it is using a UICollectionView with a scrollbar but the UICollectionView needed custom spacing padding which made the scrollbar stop in the middle of the object.
Its better to make a UICollectionView view with cell width and height the same as UICollectionView's width and height and take a UIView inside it in order to achieve custom space padding which will contain your label and text.
I just created a Sample for you.
The main idea already suggested to take a view inside the Custom Collection View cell in order to achieve custom space padding.
I have taken two IBOutlets in ViewController, a myCollectionView and a pageControl.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var pageControl: UIPageControl!
#IBOutlet weak var myCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
extension ViewController:UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
//MARK:- CollectionView Datasource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionViewCell", for: indexPath) as! CustomCollectionViewCell
return cell
}
//MARK:- CollectionView Delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.width, height: collectionView.frame.size.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
//MARK:- ScrollView Delegates
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = myCollectionView.frame.size.width;
let page = floor((myCollectionView.contentOffset.x - pageWidth / 2) / pageWidth) + 1
pageControl.currentPage = Int(page)
print(page)
}
}
scrollViewDidEndDecelerating will decide in which index you are and you can update the above mapView accordingly. A page number 0 indicates its the first cell (indexPath.row = 0). As you slide to second index, it will print 1.0 which means the second index.
This is my Custom Cell class of UICollectionViewCell
import UIKit
class CustomCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var cellView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
//To make corners round
cellView.layer.cornerRadius = 10.0
}
}
My view heirarchy
And the output
Hope you get some idea.
That bottom part looks like a UIScrollView with isPagingEnabled set to true. The 3 dots at the bottom is a UIPageControl.
Use UIScrollViewDelegate and scrollViewDidEndDecelerating to manage your other content changes.
Related
I am using UIContextMenuConfiguration for actions on a collection view cell. Everything works exactly as expected, however if my cell has (de)activated constraints from nib, it refreshes upon long press.
To demonstrate the problem, I have created a new project, with a collectionView in the storyboard. A custom cell in the collection view has a label with two constraints, a constraint pinning it to the bottom of the cell (initially active), and the other aligns it in the center (initially disabled).
Here's my code,
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.configure()
return cell
}
func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
return UIContextMenuConfiguration.init(identifier: nil, previewProvider: nil) { (array) -> UIMenu? in
return UIMenu(title: "Hello", image: nil, identifier: nil, options: .destructive, children: [UIAction(title: "Share", image: UIImage(systemName: "tray.and.arrow.up"), identifier: nil) { _ in
print("HelloWorld!")
}])
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 265, height: 128)
}
}
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var bottomConstraint: NSLayoutConstraint!
#IBOutlet weak var centerConstraint: NSLayoutConstraint!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func configure() {
bottomConstraint.isActive = false
centerConstraint.isActive = true
}
}
The issue appears to be directly related to:
two constraints created in Storyboard which would conflict with each other
setting one constraint to Not Installed
de-activating the installed constraint and activating the not-installed constraint
When initializing UIContextMenuConfiguration with previewProvider: nil - which tells UIKit to auto-generate a preview view - the "installed" states of the constraints are reset.
One way to get around it:
Instead of marking the Center constraint "not installed" give it a Priority of 998, and give the Bottom constraint a Priority of 999 (that will prevent IB from complaining).
You can then keep your configure() func as:
func configure() {
bottomConstraint.isActive = false
centerConstraint.isActive = true
}
and the label's centerY constraint will remain active in both the cell and in the context menu's preview.
However, if you WANT the previewView to look different than the cell, your best bet (and probably a better approach to begin with) is to use a custom previewProvider.
(source: uimovement.com)
I want to implement layout like the above(auto line break when screen's width is not enough to accommodate buttons' widths).
But I can't come up with any idea about how to make that image like layout. I just can implement statically, not dynamically.
In Android, there is a layout that can implement the above.
But I don't know what can help me implement the above image in swift.
Please help me.
Following #Matthew Mitchell 's suggestion.
I implemented it like below.
My ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
var hobbyArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
// self.collectionView!.register(CollectionViewCell.self, forCellWithReuseIdentifier: "cell")
hobbyArray.append("test1")
hobbyArray.append("test2")
hobbyArray.append("test3")
hobbyArray.append("test4")
hobbyArray.append("test5")
hobbyArray.append("test5")
hobbyArray.append("test5123123")
collectionView.reloadData()
}
}
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return hobbyArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.title.text = self.hobbyArray[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let text = self.hobbyArray[indexPath.row]
let cellWidth = text.size(withAttributes:[.font: UIFont.systemFont(ofSize:17)]).width + 25
return CGSize(width: cellWidth, height: 35.0)
}
}
Other codes are implemented exactly equal to #Matthew Mitchell's codes.
However, still I can't get what I wanted to implement.
I failed to make what I had wanted.
To do this efficiently you need to have a UICollectionView with a custom FlowLayout. I am going to do a storyboard example. This is quite complicated so I will try my best. All the code will be below the steps.
Step 1: Create a swift file named CollectionViewFlowLayout and use UICollectionViewLayout code in the newly created class.
Step 2: Add a UICollectionView to your ViewController
Step 3: Link new UICollectionView layout with the CollectionViewFlowLayout class
Step 4: Create a UICollectionViewCell inside the UICollectionView, add a label to that cell and constrain it to left and right in the cell and center it vertically. In the attributes inspector of the cell give it a reusable identifier ("cell" for this example)
Step 6: Create a swift file named collectionViewCell and use UICollectionViewCell class that links to your collectionViewCell (same way you linked your flowlayout in step 3).
Step 7: Add ViewController code to your ViewController Class. This code allows you to add cells to your collection view. The sizeForItemAt function will allow you to resize the cells according to the width of the string that you put inside each cell.
Code:
ViewController:
import UIKit
class viewController: UIViewController {
//Outlets
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return YOUR_ITEM_COUNT
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
self.title.text = YOUR_ITEMS_LIST[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let text = YOUR_ITEMS_LIST[indexPath.row]
let cellWidth = text!.size(withAttributes:[.font: UIFont.systemFont(ofSize:17)]).width + 25
return CGSize(width: cellWidth, height: 35.0)
}
}
UICollectionViewCell:
class CollectionViewCell: UICollectionViewCell {
//Outlets
#IBOutlet weak var title: UILabel!
}
UICollectionViewFlowLayout:
import UIKit
class CollectionViewFlowLayout: UICollectionViewFlowLayout {
var tempCellAttributesArray = [UICollectionViewLayoutAttributes]()
let leftEdgeInset: CGFloat = 0
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let cellAttributesArray = super.layoutAttributesForElements(in: rect)
//Oth position cellAttr is InConvience Emoji Cell, from 1st onwards info cells are there, thats why we start count from 2nd position.
if(cellAttributesArray != nil && cellAttributesArray!.count > 1) {
for i in 1..<(cellAttributesArray!.count) {
let prevLayoutAttributes: UICollectionViewLayoutAttributes = cellAttributesArray![i - 1]
let currentLayoutAttributes: UICollectionViewLayoutAttributes = cellAttributesArray![i]
let maximumSpacing: CGFloat = 8
let prevCellMaxX: CGFloat = prevLayoutAttributes.frame.maxX
//UIEdgeInset 30 from left
let collectionViewSectionWidth = self.collectionViewContentSize.width - leftEdgeInset
let currentCellExpectedMaxX = prevCellMaxX + maximumSpacing + (currentLayoutAttributes.frame.size.width )
if currentCellExpectedMaxX < collectionViewSectionWidth {
var frame: CGRect? = currentLayoutAttributes.frame
frame?.origin.x = prevCellMaxX + maximumSpacing
frame?.origin.y = prevLayoutAttributes.frame.origin.y
currentLayoutAttributes.frame = frame ?? CGRect.zero
} else {
// self.shiftCellsToCenter()
currentLayoutAttributes.frame.origin.x = leftEdgeInset
//To Avoid InConvience Emoji Cell
if (prevLayoutAttributes.frame.origin.x != 0) {
currentLayoutAttributes.frame.origin.y = prevLayoutAttributes.frame.origin.y + prevLayoutAttributes.frame.size.height + 08
}
}
}
}
return cellAttributesArray
}
func shiftCellsToCenter() {
if (tempCellAttributesArray.count == 0) {return}
let lastCellLayoutAttributes = self.tempCellAttributesArray[self.tempCellAttributesArray.count-1]
let lastCellMaxX: CGFloat = lastCellLayoutAttributes.frame.maxX
let collectionViewSectionWidth = self.collectionViewContentSize.width - leftEdgeInset
let xAxisDifference = collectionViewSectionWidth - lastCellMaxX
if xAxisDifference > 0 {
for each in self.tempCellAttributesArray{
each.frame.origin.x += xAxisDifference/2
}
}
}
}
You can use a UICollectionView with custom UICollectionViewFlowLayout or use a fully custom solution with UIView as root and different UIScrollViews with some custom content as lines (cells) here.
I have an example, but it's too huge to post here. Write me if you are inserting in.
I had the same problem and i found a shortest and super easy solution to make the height dynamic by subclassing UICollectionView and assign it to the CollectionView.
Here's the code:
class DynamicHeightCollectionView: UICollectionView {
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
}
override var intrinsicContentSize: CGSize {
return self.collectionViewLayout.collectionViewContentSize
}
}
I am attaching reference link to that solution.
https://stackoverflow.com/a/49297382/9738186
This question already has answers here:
Outlets cannot be connected to repeating content iOS
(9 answers)
Closed 4 years ago.
I followed the attached guide to creating static UICollectionView but now I would like to add buttons to each cell and change the text on the buttons, for example. I can not do this and get the error "UIButton is invalid. Outlets cannot be connected to repeating content." How can I fix this issue and use IBOutlets with objects in cells without leaving the ViewController?
If I need to leave ViewController please describe the process with a lot of detail as I am a beginner and am not too knowledgeable on the different view classes.
Thank you!!
Instead of the outlet between the button and the view controller, you should create a subclass of UICollectionViewCell, and add your IBOutlets on that class.
class MyCollectionViewCell: UICollectionViewCell {
#IBOutlet var myButton: UIButton!
}
Then, in Interface Builder, set this subclass to be the class of your cells (in the Identity inspector pane).
You should then be able to create the outlet connection from your button to your cell.
I hope this is clear enough. If not, please let me know!
Example code
class MyCollectionViewCell: UICollectionViewCell {
#IBOutlet var myButton: UIButton!
}
class MyViewController: UIViewController, UICollectionViewDataSource {
#IBOutlet var myCollectionView: UICollectionView!
private var isMyButtonEnabled = true
// Other view controller code
func disableMyButton() {
self.isMyButtonEnabled = false
self.myCollectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = ... as! MyCollectionViewCell // Get cell
// Other cell setup
cell.myButton.isEnabled = self.isMyButtonEnabled
return cell
}
}
Define class like following for your collection view:
class MyCollectionCell : UICollectionViewCell {
#IBOutlet weak var likeButton: UIButton?
}
Create xib for collection cell and use above custom class for collection view.
Now in your view controller define collection view and implement following delegates UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout.
class ViewController: UIViewController, UICollectionViewDataSource,
UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
#IBOutlet var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "MyCollectionViewCell", bundle: nil)
collectionView?.registerNib(nib, forCellWithReuseIdentifier: "myCell")
}
//UICollectionViewDelegateFlowLayout methods
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat
{
return 4;
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat
{
return 1;
}
//UICollectionViewDatasource methods
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell =
collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as MyCollectionCell
cell.likeButton.setTitle("myTitle", for: .normal)
cell.likeButton.tag = indexPath.row
cell.likeButton.addTarget(self, action: #selector(mainButton:), forControlEvents: .TouchUpInside)
return cell
}
#IBAction func mainButton(sender: UIButton) {
println(sender)
// use button tag to find out which button is clicked.
}
}
In above code important method is func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell where you set tag to your button and then use that tag to find out which button is pressed and use that id to find out data source or action you want to perform.
I have been trying to implement a vertical collection view inside a horizontal collection view. I have succeeded in my venture up to great extent. But when the device is rotated from portrait to landscape mode, the vertical collection view cells do not resize. Although the cells resize properly when the device enters from landscape to portrait mode. Even the horizontal collection view cells resize properly as I have invalidated the flow layout inside the viewWillTransitionToSize function. I have implemented the same function (with other functions like numberOfItemsAtIndexPath, cellForItemAt, sizeForItemAt, , etc.) for vertical collection view too (inside a class "HorizontalCollectionViewCell" in a separate CocoaTouch file). But all in vein. All the view and subviews (including the two collection views) have been created using storyboard (not code). I have been searching for the solution for last 1 week , but haven't succeeded yet. Kindly help me find a proper solution for this problem.
Here is the code inside ViewController file:-
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var horizontalView: UIView! // Container View for horizontal Collection View.
#IBOutlet weak var horizontalCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
horizontalCollectionView.delegate = self
horizontalCollectionView.dataSource = self
menuBarCollectionView.delegate = self
menuBarCollectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == menuBarCollectionView {
let cell = menuBarCollectionView.dequeueReusableCell(withReuseIdentifier: "menuButtonsCell", for: indexPath) as! MenuBarCollectionViewCell
cell.menuButtonsLabel.text = menuButtonsName[indexPath.row]
return cell
}
let cell = horizontalCollectionView.dequeueReusableCell(withReuseIdentifier: "horizontalCell", for: indexPath) as! HorizontalCollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == menuBarCollectionView {
let menuButtonWidthFactor = self.menuBarView.frame.width - 1
return CGSize(width: menuButtonWidthFactor / 3, height: 35)
}
return CGSize(width: horizontalView.frame.width, height: horizontalView.frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
if collectionView == menuBarCollectionView {
return 0.5
}
return 0
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
menuBarCollectionView.collectionViewLayout.invalidateLayout()
horizontalCollectionView.collectionViewLayout.invalidateLayout()
}
}
Here is the code inside subclass HorizontalCollectionViewCell file:-
import UIKit
class HorizontalCollectionViewCell: UICollectionViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var verticalCollectionView: UICollectionView! {
didSet {
self.verticalCollectionView.delegate = self
self.verticalCollectionView.dataSource = self
}
}
#IBOutlet weak var verticalView: UIView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = verticalCollectionView.dequeueReusableCell(withReuseIdentifier: "verticalCell", for: indexPath)
cell.backgroundColor = UIColor.red
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.verticalView.frame.width, height: 100)
}
func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
verticalCollectionView.collectionViewLayout.invalidateLayout()
}
}
I have a collectionView with different periods (day to year) for user to choose. Each item's size is equal to the size of collectionView itself.
#IBOutlet weak var periodCollectionView: UICollectionView!
#IBOutlet weak var itemLabel: UILabel!
let collectionValues = ["Day", "Week", "Month", "Year"]
var currentVisibleItem: Int?
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PeriodName", for: indexPath) as? DisplayPeriodCollectionViewCell
else {
fatalError("Unable to cast collection view cell as DisplayPeriodCollectionViewCell")
}
cell.periodName.text = collectionValues[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = collectionView.frame.height
let width = collectionView.frame.width
return CGSize(width: width, height: height)
}
What i am trying to do is get an info label to display the index of current visible item after collectionView has scrolled. Her is the code:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let centerPoint = CGPoint(x: periodCollectionView.center.x + periodCollectionView.contentOffset.x, y: 1.0)
print("centerPoint: \(centerPoint)")
if let currentItemIndexPath = periodCollectionView.indexPathForItem(at: centerPoint) {
currentVisibleItem = currentItemIndexPath.item
print("index of current item: \(currentVisibleItem!)")
itemLabel.text = "\(currentVisibleItem!)"
} else {
print("could not get index of current item...")
}
}
I've added print statements to check if values are defined correctly at runtime, and they show everything is fine. The problem is that label does not always update its text after scrolling ends, but instead waits for new scrolling to occur:
I can't figure out why this is happening - setting a breakpoint at scrollViewDidEndDecelerating shows that all code gets executed, so what's wrong with the label text?
UPD. Not-updating label text appears to be a Simulator issue - when running on device, label updates correctly.
Try this
override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let currentIndex = scrollView.contentOffset.x / CGFloat((itemWidth + interitemSpacing / 2))
print(currentIndex)
}
Please try the following code.
I used this many times in my real projects and this works fine.
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let visibleIndex = Int(targetContentOffset.pointee.x / collectionView.frame.width)
print(visibleIndex)
}
In your case you can use:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
because each item is at the same size as your collection view.
if you still want to use scroll view delegate you should write your page calculation in the following delegate functions:
func scrollViewDidEndDragging(UIScrollView, willDecelerate: Bool)
func scrollViewDidEndDecelerating(UIScrollView)
func scrollViewDidEndScrollingAnimation(UIScrollView)