问题
I'm trying to create a custom top swipe menu that has a moving resizing orange bar that denotes which tab is selected. This is an extremely common design and I'm just doing this for practice as I am new to swift. You navigate by either swiping through the bottom collectionView or you can select a tab on the top menu. The top menu is also just a collectionView and is scrollable as well.
As you can see below (first gif), my problem is that when I try to go back to the first tab, whether by swiping the bottom or by selecting the top, the orange bar does not move to the left edge of the screen as expected. Everything else works fine. However, when I turn on the debugger and insert breakpoints (second gif), the orange bar behaves as expected again.
My guess is that this has something to do with the order in which the views are updated or something to do with the timing in which the scrolling animation ends. And it must be affecting the way I am calculating the position of the orange bar. Which is why when the debugger is on and the animation is slowed down, the orange bar behaves as expected. However, since I'm pretty inexperienced, I am not sure how to pinpoint the problem.
My implementation is overriding scrollViewDidScroll
of the bottom content view, checking if the user has scrolled past more than half of the current page. If yes, then call topMenu.collectionView.setContentOffset
to scroll the top menu to its proper position and also call animateHorizontalBar(index: Int)
as shown below, which takes the index of the target page.
FYI: array
just contains Strings for the title of each tab. I am using the size of the strings to calculate the size and position of the orange bar.
EDIT: Going to first index is fine when I disabled the feature when the horizontal bar will follow the selected tab when top menu is scrolled (second gif)
Any help will be greatly appreciated. Thanks!
func moveHorizontalBar(index: Int) {
let horizontalBar = topMenu.horizontalBarView
var sizeArray: [CGFloat] = []
for item in array {
sizeArray.append((ceil(40 + (item as NSString).size(withAttributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 25, weight: UIFont.Weight.medium)]).width)))
}
let width = self.view.frame.width
let ratio = (topMenu.collectionView.contentSize.width - width) / (collectionView.contentSize.width - width)
let offset = CGFloat(index) * width * ratio
if index == 0 {
horizontalBar.frame.origin.x = 0.0
horizontalBar.frame.size.width = sizeArray[index]
} else {
var x: CGFloat = 0.0
for i in 0..<index {
x += sizeArray[i]
}
topMenu.currentOffset = x
horizontalBar.frame.origin.x = x - offset
horizontalBar.frame.size.width = sizeArray[index]
}
}
func animateHorizontalBar(index: Int, animated: Bool) {
if animated {
self.topMenu.isSelectingNewTab = true
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.moveHorizontalBar(index: index)
})
} else {
moveHorizontalBar(index: index)
}
}
来源:https://stackoverflow.com/questions/54357768/ios-custom-top-segmented-control-works-as-expected-only-when-using-debugger