Is it possible to go to the specific page with PageControl Dots? - ios

I face with a problem about UIPageControl dots. For instance, I made a banner with scrollview and I would like to travel in banner items by clicking dots of page control added below banner scroll view, but I couldn't find any proper option to go to the specific item by touching related page control dot.
Ex. There are 5 banner items and naturally 5 page control dots. Initially it stars from beginning and continues to the right one after another, how can I directly go to the 3. item by clicking 3. dot?
My banner and pagecontrol dots
This is my code for changing banner item with scrolling in scroll view:
pageControl.addTarget(self, action: #selector(pageControlTapped(sender:)), for: .touchUpInside)
#objc func pageControlTapped(sender: UIPageControl) {
let nextPage = self.pageControl.currentPage + 1
let newPage = nextPage < self.pageControl.numberOfPages ? nextPage : 0
let indexPath = IndexPath(row: newPage, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: .left, animated: true)
}

I think you should use the "valueChanged" event instead of "touchUpInside" for pageControl.
Example:
pageControl.addTarget(self, action: #selector(pageControlTapped(sender:)), for: .valueChanged)
#objc func pageControlTapped(sender: UIPageControl) {
let nextPage = sender.currentPage
let indexPath = IndexPath(row: nextPage, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: .left, animated: true)
}

Related

How to scroll to Tableview Top in Pagination?

I have pagination in my tableview and I scroll to bottom close to 5-6 pagination iterations down.
How do I scroll to top of the UITableview.
Solutions that I have tried with SO solutions
Sol 1:
DispatchQueue.main.async {
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
Sol 2:
DispatchQueue.main.async {
self.tableView.setContentOffset(.zero, animated: true)
}
Sol 3:
tableView.scroll(to: .top, animated: true)
Sol 4:
https://stackoverflow.com/a/48018130
whenever I am trying, I have checked the Scrollview contentsize of the tableview
The overall scroll is
tableview.scrollview contentSize = [(414.0, 30662.666544596355)]
when I tap on the button to scroll to top = [(0.0, 28960.0)], gradually it is decreasing, Ideally it should to top and make [(0.0, 0.0)] right ?
How can I achieve it ?

CollectionView scroll with button tap scrollToItem not working

I currently have a login and signup buttons labeled as 1 and 2. And underneath that, I have a collectionView with two cells (one for the login UI and one for register UI). When I click on the signup button(Label 2), I want to move the collectionView to the next cell.
I tried using the scrollToItem, but it does not do anything. Anyone know why?
#objc private func didTapRegisterButton() {
let i = IndexPath(item: 1, section: 0)
self.onboardingCollectionView.scrollToItem(at: i, at: .right, animated: true)
}
Figured it out. My collectionView had isPagingEnabled property as true. The scrollToItem doesn't work if that is set to true.
If you want to scroll between two cells on button click then first you need to uncheck(disable) Scrolling Enabled property and check(enable) Paging Enabled property of collectionView. (With this approach user can't scroll manually with swipe)
On button first action,
if self.currentIndexPath == 0 {
return
} else {
self.currentIndexPath += 1
self.yourCollectionView.scrollToItem(at: IndexPath(row: self.currentVisibleIndexPath, section: 0), at: .centeredHorizontally, animated: true)
}
On button second action,
if self.currentIndexPath == 1 {
self.currentIndexPath -= 1
self.yourCollectionView.scrollToItem(at: IndexPath(row: self.currentVisibleIndexPath, section: 0), at: .centeredHorizontally, animated: true)
} else {
return
}
And declare global variable
var currentIndexPath: Int = 0

Creating custom VoiceOver rotor to navigate UICollectionView vertically

I have a large square grid (225 cells) constructed as a 2d UICollectionView and I would like blind users to be able to navigate the grid easily. Currently they would need to scroll horizontally through every square to go down. Ideally, I'd like to have a custom VoiceOver rotor that allows for left, right, up and down swiping to navigate. Is this possible?
If not, I would settle for having a custom rotor which moves up and down via left/right swipe. I've attempted to create one by getting the current indexPath and using the scrollToItem method to change it. The rotor can be selected but has no effect currently so I've done it wrong so far.
private func setupVerticalRotor() -> UIAccessibilityCustomRotor {
let vertRotorOption = UIAccessibilityCustomRotor.init(name: "Move vertically") { (predicate) -> UIAccessibilityCustomRotorItemResult? in
let forward = predicate.searchDirection == UIAccessibilityCustomRotor.Direction.next
let visibleCells = self.collectionView.visibleCells
if let firstCell = visibleCells.first {
if let indexPath = self.collectionView.indexPath(for: firstCell as UICollectionViewCell) {
if forward {
let newIndexPath = IndexPath(row: indexPath.row, section: indexPath.section + 1)
self.collectionView.scrollToItem(at: newIndexPath, at: UICollectionView.ScrollPosition.centeredVertically, animated: false)
}else {
let newIndexPath = IndexPath(row: indexPath.row, section: indexPath.section - 1)
self.collectionView.scrollToItem(at: newIndexPath, at: UICollectionView.ScrollPosition.centeredVertically, animated: false)
}
}
}
return UIAccessibilityCustomRotorItemResult.init(targetElement: self.collectionView , targetRange: nil)
}
return vertRotorOption
}
Ideally, I'd like to have a custom VoiceOver rotor that allows for left, right, up and down swiping to navigate. Is this possible?
The native rotor has already the item to navigate vertically.
For your code, I suggest to take a look at this custom rotor example + check your collection view cells update with breakpoints in Xcode.

UICollectionView scrollRectToVisible and scrollToItem break user scroll

I am using this code to reveal a specific item in a collection view.
var pages: [PDFPage]?
var currentPage: PDFPage?
override func viewDidLayoutSubviews() {
// Scroll to currently opened page
if let current = currentPage, let idx = pages?.firstIndex(of: current) {
collectionView?.scrollToItem(at: IndexPath(item: idx, section: 0), at: .centeredVertically, animated: false)
}
}
It is working as expected but it completely locks user scrolling in order, I guess, to always keep the item in the requested position.
The same happens when using scrollRectToVisible.
Instead I'd like it to only move to the item, and then let the user scroll wherever he wants. Which is the behaviour I'm getting with UITableViewController's scrollToRow.
Am I missing something?
Turns out calling the scroll in viewDidLayoutSubviews was the issue, because it was continuously repeated and preventing any further scroll. I solved the issue like this:
var currentPage: PDFPage?
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Scroll to currently opened outline
if let current = currentPage, let idx = pages?.firstIndex(of: current) {
collectionView?.scrollToItem(at: IndexPath(item: idx, section: 0),
at: .top,
animated: false)
// In order to only run the scroll once, without locking the view
currentPage = nil
}
}

UISwipeGestureRecognizer and CollectionView scroll to next item indexPath

So I have a collection view of cards, and what I want is when I swipe left I want the next item to be centered in the middle, this doesn't work with paging enabled
So when I swipe left I want the next card to be centered, this doesn't work with the normal behaviour because I just want to swipe one card.
So I have added UISwipeGestureRecognizer and disabled scrolling on the collection view
class ViewController: UIViewController,UICollectionViewDataSource {
#IBOutlet var joke_cards: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad();
//Add gestures
let leftSwipeGest = UISwipeGestureRecognizer(target: self, action: #selector(funcForGesture))
leftSwipeGest.direction = .left
joke_cards.addGestureRecognizer(leftSwipeGest)
}
func funcForGesture(sender: UISwipeGestureRecognizer){
if sender.direction == .left {
//scroll to next item
}
}
Now my problem is how can I scroll to the next item? since I don't know the indexPath? because if I want to use this self.joke_cards.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true), I will need the index path, so I think I need to figure out the current indexPath on the view and add one when the user swipes.
Any suggestions?
//updated
So I have managed to get it to work, but it only works when I swipe the first time:
func funcForGesture(sender: UISwipeGestureRecognizer){
if sender.direction == .left {
//scroll to next item
let cellItems = self.joke_cards.indexPathsForVisibleItems
let next = cellItems[0] as! IndexPath
self.joke_cards.scrollToItem(at: next, at: .centeredHorizontally, animated: true)
}
}
One solution:
1: Add an NSIndexPath property to your cells and just set the indexPath to the property in your cellForItem method.
2: Get an array of visible cells.
3: Get the rect of the visible cells and calculate their position on the screen and you can allso get the correct indexPath from the cell property.
Second solution:
1: Add a UILongPressGestureRecognizer to your cell contentView
2: Set minimumPressDuration to 0.
3: Add delegate methods to fire acitons or this.
Third solution:
1: Keep your swipe gesture.
2: And use this method (same as option 2) indexPathForItemAtPoint:
Why are you saying that this does not work with paging enabled? This should actually be the best way to do it in my opinion. You can just make the width of the UICollectionViewCells to be equal to the width of the UICollectionView, set the scroll direction to be horizontal and enable paging, that should do the trick.
In this way you won't need any UIGestureRecognizers.
Ok so the solution is this one:
#IBOutlet var joke_cards: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad();
//Add gestures
let leftSwipeGest = UISwipeGestureRecognizer(target: self, action: #selector(funcForGesture))
leftSwipeGest.direction = .left
joke_cards.addGestureRecognizer(leftSwipeGest)
}
func funcForGesture(sender: UISwipeGestureRecognizer){
if sender.direction == .left {
//scroll to next item
let cellItems = self.joke_cards.indexPathsForVisibleItems
self.joke_cards.scrollToItem(at: cellItems.max()!, at: .centeredHorizontally, animated: true)
}
}

Resources