issue while changing the CurrentPage of UIPageControl which is Inside a TableViewCell - ios

am trying to create a Carousel inside tableViewCell and am almost there but am having difficulty while implementing the UIPageControl in my TableView so that when CollectionViewCell's (which is inside tableViewCell) Item got changed i can show it on UIPageControl,
i tried the below solution and encountered a strange behaviour (maybe its strange for only me ) , when the View Loads and i change my item (which is in collectionViewCell) the PageControl's currentPage is not changing but after scrolling down to the end of tableView and coming back to top its working fine ,
suppose you have 6 rows and you scroll down to row 6 and then when you scroll up to row 5 and change its item the pageControl will work , if you keep doing this until reaching the top it'll going to work fine but if you go from row 5 to 6 and change row 6's item then its not going to work
i am initialising my pageControl in cellForRowAtIndexPath :
pagerControll = cell.pageControll
then trying to change the position by listening to ScrollView's contentOffSet
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if scrollView != tableView {
if scrollView.contentOffset.x >= self.view.frame.size.width && scrollView.contentOffset.x < (self.view.frame.size.width * 2){
pagerControll.currentPage = 1
}else if scrollView.contentOffset.x >= (self.view.frame.size.width * 2 ) {
pagerControll.currentPage = 2
}else {
pagerControll.currentPage = 0
}
print(scrollView.contentOffset) }
}
any idea why this is happening ?? or how to fix this ??
P.s if question is not clear enough then let me know , i'll add some more detail
UPDATE:
when view loads and am changing the item of collectionViewCell the below cell's pageControl's currentPage is Changing

after getting pissed off , WE MADE IT
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if scrollView != tableView {
let currentCells = tableView.visibleCells
let cell = currentCells[0] as! NotesTableViewCell
if scrollView.contentOffset.x >= self.view.frame.size.width && scrollView.contentOffset.x < (self.view.frame.size.width * 2){
cell.pageControll.currentPage = 1
}else if scrollView.contentOffset.x >= (self.view.frame.size.width * 2 ) {
cell.pageControll.currentPage = 2
}else {
cell.pageControll.currentPage = 0
}
}
}

Related

pull up to reload in collectionview using uiview

i have a collection view which is used to show comment and i am using a uiview at bottom of the view controller with a height of 0.
when user reach the bottom of content in collection view,as he pull up past content i check in scrollviewdidscroll
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if self.comment.count >= 5 {
let offseety = scrollView.contentOffset.y
let contenthight = scrollView.contentSize.height
if offseety > contenthight - scrollView.frame.size.height + 5 && offseety > 50{
if self.viewheight.constant < 50 {
self.viewheight.constant = scrollView.frame.size.height - contenthight + offseety
if offseety > contenthight - scrollView.frame.size.height + 50{
self.anddiii.isHidden = false
self.anddiii.startAnimating()
self.anothershit.isHidden = false
self.anothershit.text = "Loading more"
}
}}else{
}
}
}
but problem after scrolling end the collection view scrolls back,is there a way to put an ofset bellow last collection cell to show uiview in
Try Below code:
self.collectionView.contentInset = UIEdgeInsetsMake(0,0,55,0)

Change ScrollView Page When Scrolled Horizontally but not Vertically

I have a scroll view that contains 2 UITableViews. In other words, page 0 contains UITableView 0 and page 1 contains UITableView 1. At the top of the view, I have a segmented control. When a user swipes between pages, the highlighted segmented control changes. I.e. when the user is on Page 0 and they change to page 1, the segmented control that is highlighted also changes from page 0 to page 1.
My problem is that when the the current page is "Page 1" and I scroll vertically through my UITableView, my function changes the segmented control index to 0. If the user is on page 1 and they scroll vertically on the UITable, I do not want the index to be changed. I have provided my function to change the segmented control index below.
I have tried including && yOffset == 0 to my if statement, however it does not work because I believe Y == 0 for a brief moment in time.
Any help is much appreciated.
Thanks.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var previousPage : NSInteger = 0
let pageWidth : CGFloat = scrollView.frame.size.width
let fractionalPage = Float(scrollView.contentOffset.x / pageWidth)
let page = lroundf(fractionalPage)
let yOffset = Float(scrollView.contentOffset.y / pageWidth)
if previousPage != page {
previousPage = page
}
segments.selectedSegmentIndex = previousPage
segments(nil)
}
EDIT - SOLUTION:
Solution provided by Dhaval D. works perfectly. Prior to performing the page change, check to see whether or not the scroll was performed by the UITableView. Thank you for your help!
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Check whether scrolling is performed by UITableView then ignore page counter related stuff
if scrollView != tableView0 && scrollView != tableView1 {
var previousPage : NSInteger = 0
let pageWidth : CGFloat = scrollView.frame.size.width
let fractionalPage = Float(scrollView.contentOffset.x / pageWidth)
let page = lroundf(fractionalPage)
let yOffset = Float(scrollView.contentOffset.y / pageWidth)
if previousPage != page {
previousPage = page
}
segments.selectedSegmentIndex = previousPage
segments(nil)
}
}
You can do this by either matching your UITableView objects in your scrollViewDidScroll like below or you can compare your UIScrollView object for which you want to calculate PageNo or you want to change segment control for showing current selection.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Check whether scrolling is performed by UITableView then ignore page counter related stuff
if scrollView != tableView0 && scrollView != tableView1 {
var previousPage : NSInteger = 0
let pageWidth : CGFloat = scrollView.frame.size.width
let fractionalPage = Float(scrollView.contentOffset.x / pageWidth)
let page = lroundf(fractionalPage)
let yOffset = Float(scrollView.contentOffset.y / pageWidth)
if previousPage != page {
previousPage = page
}
segments.selectedSegmentIndex = previousPage
segments(nil)
}
}

Scroll view when collection view scrolls

I want to scroll the UIView when collection view scrolls as shown in below video
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print(scrollView.contentOffset.x)
let contentSize = self.propertyImageCollectionView.contentSize
let xOffSet = (((scrollView.contentOffset.x * self.propertyImageCollectionView.frame.width) / (contentSize.width - self.progressViewWidthConstratint.constant)))
let xValue = xOffSet + ((self.progressViewWidthConstratint.constant * self.progressViewLeadingConstraint.constant) / self.propertyImageCollectionView.frame.width)
print( self.progressViewWidthConstratint.constant)
print( xOffSet)
print(xValue)
if xValue > 0 && xValue < self.propertyImageCollectionView.frame.width - self.progressViewWidthConstratint.constant{
self.progressViewLeadingConstraint.constant = xValue
}
}
The view is not scrolling upto end of screen. It stops scrolling before some points. Where am I lacking in my code. I also tried to use KVO but not succeed. Do you have any alternative approach?

I want to make effect similar to resizing top view on contacts app?

Native contacts app has interesting effect - when user tries to scroll, the scroll view pushes the top view with avatar and only when top view is in "small mode" it is scrolled up.
I was able to resize view on scrolling, via didScroll method. But problem is, content offset is also changing while i push the top vied. In native contacts, content offset changes only when top view is in "small mode"
Any suggestions, how did they made this?
Here's a sample project of how you could do it:
https://github.com/lukaswuerzburger/resizeable-tableview-header
You simply have a view controller with a table view and a custom view (resizable header) in it. On scrollViewDidScroll you change the height constraint.
PS: The transitions between the master and detail view controller are not prefect, but maybe someone can help me with that. The change of navigationBar's backgroundImage and shadowImage doesn't really work animated when popping back to the master view controller.
The bounty answer is good, but it still gives somewhat choppy solution to this problem. If you want exacly like native this is your solution. I have been playing a lot lately with collection views, and have gained much more experience. One of the things that I found is that this problem can easily be solved with custom layout:
class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
let minHeightForHeader: CGFloat = 50
let offsetFromTop: CGFloat = 20
override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
// get current attributes
let attributes = super.layoutAttributesForSupplementaryView(ofKind: elementKind, at: indexPath)
// get first section
if let attributes = attributes, elementKind == UICollectionElementKindSectionHeader && indexPath.section == 0 {
if let collectionView = collectionView {
// now check for content offset
var frame = attributes.frame
let yOffset = collectionView.contentOffset.y
if yOffset >= -offsetFromTop {
let calculatedHeight = frame.size.height - (yOffset + offsetFromTop)
let maxValue = minHeightForHeader > calculatedHeight ? minHeightForHeader : calculatedHeight
frame.size.height = maxValue
attributes.frame = frame
}
else {
frame.origin.y = offsetFromTop + yOffset
attributes.frame = frame
}
}
return attributes
}
// default return
return attributes
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
Just replace your default layout with this custom class and add this line somewhere in your setup method
flowLayout.sectionHeadersPinToVisibleBounds = true
Voila!
EDIT: Just one more optional method for clipping part, when you scroll to certain part, scroll might continue or return:
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
if let collectionView = collectionView {
let yOffset = collectionView.contentOffset.y
if yOffset + offsetFromTop >= maxHeightForHeader / 2 && yOffset + offsetFromTop < maxHeightForHeader && !(velocity.y < 0) || velocity.y > 0{
return CGPoint.init(x: 0, y: maxHeightForHeader - minHeightForHeader - offsetFromTop)
}
if yOffset + offsetFromTop < maxHeightForHeader / 2 && yOffset + offsetFromTop > 0 || velocity.y < 0 {
return CGPoint.init(x: 0, y: -offsetFromTop)
}
}
return proposedContentOffset
}

Scrolling collection view with UIViews on top?

I have a UICollectionViewController and I added two UIViews as subviews. One is the purple UIView and above it is another white UIView, with the blue collection view getting scrolled up behind both.
Below those UIViews, I made the collectionView.contentInset from the top 300 (that's the total size of two UIViews' height). What I'm trying to accomplish is to scroll the collection view along with the two UIViews above. It's almost similar to the solution on this thread (Move a view when scrolling in UITableView), except when I override scrollViewDidScroll, the whole frame gets scrolled up and cells go behind the two Views. All I want is to scroll up the UIViews, and then scroll through the collection views. I feel like this might involve nested scroll views.
This was how I overrode scrollViewDidScroll:
var rect = self.view.frame
rect.origin.y = -scrollView.contentOffset.y - 300
self.view.frame = rect
EDIT: I posted a video that demonstrates what I want to do per iOS Tumblr app: https://youtu.be/elfxtzoiHQo
I have achieved the same requirement through some basic steps as below.
//Declare the view which is going to be added as header view
let requiredView = UIView()
//Add your required view as subview of uicollectionview backgroundView view like as
collectionView.backgroundView = UIView()
collectionView.backgroundView?.addSubview(requiredView)
//After that control the frame of requiredHeaderView in scrollViewDidScroll delegate method like
func scrollViewDidScroll(scrollView: UIScrollView) {
let per:CGFloat = 60 //percentage of required view to move on while moving collection view
let deductValue = CGFloat(per / 100 * requiredView.frame.size.height)
let offset = (-(per/100)) * (scrollView.contentOffset.y)
let value = offset - deductValue
let rect = requiredView.frame
self.requiredView.frame = CGRectMake(rect.origin.x, value, rect.size.width, rect.size.height)
}
It sounds like what you want is a header.
you can specify a class or nib for the header with either of these:
self.collectionView.registerClass(_:, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier:)
registerNib(_:, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: )
you should also specify a reference height if you are using a flow layout: self.flowLayout.headerReferenceHeight = ...
then you can provide the header via your UICollectionViewController in: collectionView(_:, viewForSupplementaryElementOfKind:, at:) by checking for the section header kind.
Here is a decent tutorial on this for reference: https://www.raywenderlich.com/78551/beginning-ios-collection-views-swift-part-2
You have a library CSStickyHeaderFlowLayout
From the ReadMe:
UICollectionView replacement of UITableView. Do even more like Parallax Header, Sticky Section Header. Made for iOS 7.
Try this.
headerViewYConstraint is header view's top y constraint.
Stores the last contact offset.
var lastContentOffset: CGFloat = 0
override func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView != contentScrollView {
if scrollView.dragging || scrollView.decelerating {
let newOffset = scrollView.contentOffset.y
let headerViewHeight = headerView.frame.width
if headerViewHeight > 0 && scrollView.contentSize.height > view.frame.height + headerViewHeight{
var topOffset = newOffset == 0 ? 0.0 : (headerViewYConstraint.constant + lastContentOffset - newOffset)
topOffset = min(0, max(topOffset, -headerViewHeight))
if headerViewYConstraint.constant > topOffset || newOffset < headerViewHeight || lastDirectionalContentOffset - newOffset > cellHeight(){
headerViewYConstraint.constant = topOffset
}
} else {
headerViewYConstraint.constant = 0
}
lastContentOffset = newOffset
}
}
}

Resources