I'm using https://github.com/OfTheWolf/TwitterProfile <- this library on my project.
It is the little bit application of XLStripPager.
Because I have to set the header View and pager.
The layout architecture is
My Problem is this. When I set the expand the table cell label using UITableView.automaticDimension
expanding animation(?) is well worked. but after I scroll the table, the content offset.y is reset to zero. so even I tapped the bottom cell to expand, after that cell expanded when I move the scroll, the scrollView is set to the top(awkard...)
extension BottomViewController: LabelCellDelegate {
func expand(cell: LabelCell) {
let indexPath = cell.indexPath
if !expandCheck[indexPath!.row] {
expandCheck[indexPath!.row] = true
}
//offset = tableView.contentOffset.x
tableView.performBatchUpdates({ () -> Void in
cell.label.numberOfLines = 0
}, completion: nil)
}
}
I tried to print the scrollView Offset.
After click(expand) the cell the offset.y changed to 0...
I don't know how to solve this problem.
I try to assign the right before the expand contentOffset.y at the scrollViewDidScroll but breaking error.
How to prevent the reset to zero offset ? Any other method ?
I have to collection view with different cell width but equal number of cell. let say collectionview cell is equal to screen width and other collectionview cell width is about 60 pixel.
What I want is when I scoll Larger cell large cell collectionView small collectionview also scroll with respect to its content of set.
What I have tried so far is
func updateColoredView(_ scrollView: UIScrollView){
let scrollX = (screenWidth) / 60.0
if ((scrollView.contentOffset.x) / scrollX) < 16{
smallCollectionView.contentOffset.x = 16.0
}else{
smallCollectionView.contentOffset.x = ((scrollView.contentOffset.x) / scrollX)
}
}
With the image above, I would like to know/detect if the UIView 3 has reached the top of the UIScrollView.
What I did so far is to get the offSet of the UIView within the UIScrollView then check if it's less than or equal to 0 (zero).
let offsetY = scrollView.convert(myView.frame, to: nil).origin.y
if offsetY <= 0 {
print("myView is at Top")
}
But the code above is surely wrong! anybody who has an idea?
TIA!
Just convert the top of the scroll view and the top of v3 to the same coordinate system and now you can simply look to see which one is higher.
Let sv be the scroll view and v3 be view 3. Then:
func scrollViewDidScroll(_ sv: UIScrollView) {
let svtop = sv.frame.origin.y
let v3top = sv.superview!.convert(v3.bounds.origin, from:v3).y
if v3top < svtop { print("now") }
}
I'm actually not seeing anything wrong with your approach. Since according to the documentation, when view is nil, the method converts to window based coordinates:
Parameters
rect
A rectangle specified in the local coordinate system (bounds) of the receiver.
view
The view that is the target of the conversion operation. If view
is nil, this method instead converts to window base coordinates.
Otherwise, both view and the receiver must belong to the same
UIWindow object.
Another option if you don't want to assume the scroll view has a superview.
func scrollViewDidScroll(_ sv: UIScrollView) {
// The view we want to check if it's at the top of the scroll view
//let viewThatMayBeAtTop = UIView()
// get how far in the scroll view this view is
let yInScrollViewWithoutScroll = sv.convert(viewThatMayBeAtTop.bounds, from: viewThatMayBeAtTop).minY
// How far we've scrolled down
let scrolledAmount = sv.adjustedContentInset.top + sv.contentOffset.y
// If how far we've scrolled is equal or greater than the y position of the view, then it's at the top or higher
let isScrolledToTopOrHigher = scrolledAmount >= yInScrollViewWithoutScroll
if isScrolledToTopOrHigher {
print("now")
}
}
I have a UICollectionView filled with dates ranging from one date to another. I have implemented the UICollectionView with IGListKit. I would Like to enable paging on each cell so that each cell will land in the middle of the circle when it scrolls past it. (Like below) I have tried a few ways of paging, but these don't centre directly in the middle of the circle (As seen in the second image). What is happening is, the cells are getting paged to the left-hand side, I would like there to be an inset of 20 so that it fits into the circle
To enable the current date to show on the left-hand side in the circle when the view first loads, I have the semantic set to Force Right-to-Left and I also have edgeInsets which are:
left: screenWidth-62, right: 20)
The width of the cell is 42 and the inset at the side is 20, therefore the first cell will sit in the circle with these insets. So when the view first loads, the collection view looks like this:
I basically want each cell to land inside of this circle when it scrolls past (if the scrolling stops)
This is what I have so far:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if scrollView == self.collectionView {
var currentCellOffset = self.collectionView.contentOffset
currentCellOffset.x += (self.collectionView.frame.width / 2) + 20
if let indexPath = self.collectionView.indexPathForItem(at: currentCellOffset) {
self.collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
}
and this:
collectionView.decelerationRate = UIScrollView.DecelerationRate.fast
Does anyone know how to solve this?
Thank you
i created a custom collection view layout for paging by cell instead of screen
i also outline a few different ways to customize it with examples in the README
check it out here
let me know if you have any questions about it or need more help
I have a NSTableView and want to track the position of its containing NSCells when the tableView got scrolled by the user.
I couldn’t find anything helpful. Would be great if someone can lead me into the right direction!
EDIT:
Thanks to #Ken Thomases and #Code Different, I just realized that I am using a view-based tableView, using tableView(_ tableView:viewFor tableColumn:row:), which returns a NSView.
However, that NSView is essentially a NSCell.
let cell = myTableView.make(withIdentifier: "customCell", owner: self) as! MyCustomTableCellView // NSTableCellView
So I really hope my initial question wasn’t misleading. I am still searching for a way how to track the position of the individual cells/views.
I set the behaviour of the NSScrollView (which contains the tableView) to Copy on Scroll in IB.
But when I check the x and y of the view/cells frame (within viewWillDraw of my MyCustomTableCellView subclass) it remains 0, 0.
NSScrollView doesn't use delegate. It uses the notification center to inform an observer that a change has taken place. The solution below assume vertical scrolling.
override func viewDidLoad() {
super.viewDidLoad()
// Observe the notification that the scroll view sends out whenever it finishes a scroll
let notificationName = NSNotification.Name.NSScrollViewDidLiveScroll
NotificationCenter.default.addObserver(self, selector: #selector(scrollViewDidScroll(_:)), name: notificationName, object: scrollView)
// Post an intial notification to so the user doesn't have to start scrolling to see the effect
scrollViewDidScroll(Notification(name: notificationName, object: scrollView, userInfo: nil))
}
// Whenever the scroll view finished scrolling, we will start coloring the rows
// based on how much they are visible in the scroll view. The idea is we will
// perform hit testing every n-pixel in the scroll view to see what table row
// lies there and change its color accordingly
func scrollViewDidScroll(_ notification: Notification) {
// The data's part of a table view begins with at the bottom of the table's header
let topEdge = tableView.headerView!.frame.height
let bottomEdge = scrollView.bounds.height
// We are going to do hit-testing every 10 pixel. For best efficiency, set
// the value to your typical row's height
let step = CGFloat(10.0)
for y in stride(from: topEdge, to: bottomEdge, by: step) {
let point = NSPoint(x: 10, y: y) // the point, in the coordinates of the scrollView
let hitPoint = scrollView.convert(point, to: tableView) // the same point, in the coordinates of the tableView
// The row that lies that the hitPoint
let row = tableView.row(at: hitPoint)
// If there is a row there
if row > -1 {
let rect = tableView.rect(ofRow: row) // the rect that contains row's view
let rowRect = tableView.convert(rect, to: scrollView) // the same rect, in the scrollView's coordinates system
let visibleRect = rowRect.intersection(scrollView.bounds) // the part of the row that visible from the scrollView
let visibility = visibleRect.height / rowRect.height // the percentage of the row that is visible
for column in 0..<tableView.numberOfColumns {
// Now iterate through every column in the row to change their color
if let cellView = tableView.view(atColumn: column, row: row, makeIfNecessary: true) as? NSTableCellView {
let color = cellView.textField?.textColor
// The rows in a typical text-only tableView is 17px tall
// It's hard to spot their grayness so we exaggerate the
// alpha component a bit here:
let alpha = visibility == 1 ? 1 : visibility / 3
cellView.textField?.textColor = color?.withAlphaComponent(alpha)
}
}
}
}
}
Result:
Update based on edited question:
First, just so you're aware, NSTableCellView is not an NSCell nor a subclass of it. When you are using a view-based table, you are not using NSCell for the cell views.
Also, a view's frame is always relative to the bounds of its immediate superview. It's not an absolute position. And the superview of the cell view is not the table view nor the scroll view. Cell views are inside of row views. That's why your cell view's origin is at 0, 0.
You could use NSTableView's frameOfCell(atColumn:row:) to determine where a given cell view is within the table view. I still don't think this is a good approach, though. Please see the last paragraph of my original answer, below:
Original answer:
Table views do not "contain" a bunch of NSCells as you seem to think. Also, NSCells do not have a position. The whole point of NSCell-based compound views is that they're much lighter-weight than an architecture that uses a separate object for each cell.
Usually, there's one NSCell for each table column. When the table view needs to draw the cells within a column, it configures that column's NSCell with the data for one cell and tells it to draw at that cell's position. Then, it configures that same NSCell with the data for the next cell and tells it to draw at the next position. Etc.
To do what you want, you could configure the scroll view to not copy on scroll. Then, the table view will be asked to draw everything whenever it is scrolled. Then, you would implement the tableView(_:willDisplayCell:for:row:) delegate method and apply the alpha value to the cells at the top and bottom edges of the scroll view.
But that's probably not a great approach.
I think you may have better luck by adding floating subviews to the scroll view that are partially transparent, with a gradient from fully opaque to fully transparent in the background color. So, instead of the cells fading out and letting the background show through, you put another view on top which only lets part of the cells show through.
I just solved the issue by myself.
Just set the contents view postsBoundsChangedNotifications to true and added an observer to NotificationCenter for NSViewBoundsDidChange. Works like a charm!