How to fix highlighted state UIButton delay in UIPageViewController page? - ios

I have a screen in which I have a UIPageViewController in each page I have a UIButton. The problem is that there is a delay of the pressed/highlighted state of the button for about a half second when the user presses the button. both state images are set to the button using the storyboard.
This happens in the Simulator as well as on a real device.
Now from my Google searches, I came across a few posts that describe this issue, for example:
UIButton delayed state change
and:
UIbutton only looks clicked (highlighted) on longPress?
In all posts, the solution is to use the delaysContentTouches setting and set it to false.
The problem is: I didn't found how would I apply this in my case of a UIPageViewController. most of the posts talk this issue in a UIScrollView or a UITableView.
So, the question is: how would I do that in case of a UIPageViewController? I didn't see that UIPageViewController has this setting and didn't find any other way to apply it.

Found a solution to this issue, This piece of code will fix the button highlighted click delay but will prevent the pager scroll on the button itself.
public override func viewDidAppear(_ animated: Bool) {
for view in self.view.subviews {
if view is UIScrollView {
(view as? UIScrollView)!.delaysContentTouches = false
}
}
}
The reason I didn't find this in UIPageViewController is that UIPageViewController is not a subclass of UIScrollView as I expected but it contains it as a subview.

Related

UISegmentedControl Set Selected Index Without Animation

I have a UITabBarController with 3 views. Each view has a UISegmentedControl in its navigation bar, and all of these segmented controls need to remain in sync. Each time the selectedSegmentIndex on one of them changes, I fire an event that causes the others to change their selectedSegmentIndex as well. I also set the index in viewDidLoad to ensure it is correct the first time the view is displayed.
This all works as expected, except that when I switch to a different view I can see the segmented control animate its button to the correct position, even though the selectedSegmentIndex may have been set much earlier.
Can anyone tell me what is going on here? Is there a way to disable this animation (when setting the index programmatically)?
Here is the working solution from the comments:
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
UIView.performWithoutAnimation {
segmentedControl.selectedSegmentIndex = 0
segmentedControl.layoutIfNeeded()
}
}
I know this answer is very late but in case anyone else needs same solution;
Layer of subviews of SegmentedControl has their own animation. Which are;
SelectionScale
SelectionPosition
SelectionBounds
here is a sample code from my project, I wrote whole new class for my UISegmentedControl
let foregroundIndex = numberOfSegments
if subviews.indices.contains(foregroundIndex),
let foregroundImageView = subviews[foregroundIndex] as? UIImageView {
foregroundImageView.layer.removeAllAnimations()
}
this is going to remove all animations over the selected UISegment and there will be no transition, it'll just snap.

backBarButtonItem becomes visible on iOS 10 when titleView has constraints

Having a very weird behavior on iOS 10. Assume you have an empty app, created with a Master-Detail Application template. Place any UIView as a titleView in navigationBar for detail viewcontroller. Place any UIView to the right bar button items.
Then, write that code to configureView method:
if let item = self.splitViewController?.displayModeButtonItem {
self.navigationItem.leftBarButtonItem = item
self.navigationItem.leftItemsSupplementBackButton = true
}
Then configure splitviewcontroller preferredDisplayMode = .allVisible, so the displayModeButtonItem could appear.
On iOS 9 and lower this results in a standard behavior: the detail viewcontroller displays displayModeButtonItem expand button on a left side.
When user taps it, the icon transforms to an arrow. Tapping an arrow reverses button state.
On iOS 10 displayModeButtonItem displays as expand button, but if user taps it, it disappears.
Meanwhile, the button is still there and a user can tap it one more time. After that, displayModeButtonItem appears again with expand icon and backButtonItem icon as well. Just like it appears when we push another viewcontroller onto detail's navigationcontroller:
But in that case both of icons acts as displayModeButtonItem.
Is this an iOS bug, or a misconfig? What can I do to get normal button behavior?
Edit: I found out, that everything works as expected, if a titleView (of rightBarButtonItem's view) does not contain any constraints on it's child views. Filed a radar on this.
Edit 2: Some controls (like UIImageView) may implicitly add NSContentSizeLayoutConstraint, so, to prevent this behavior (and prevent the bug above), subclass it and override intrinsicContentSize method like this:
private class NoConstraintsUIImageView: UIImageView {
private override func intrinsicContentSize() -> CGSize {
// prevent implicit NSContentSizeLayoutConstraint adding in updateConstraints
return CGSize(width: UIViewNoIntrinsicMetric, height: UIViewNoIntrinsicMetric)
}
}

Why is my navigation item/bar very dark in colour?

I am building a help screen view controller of my app. It basically contains a UIWebView because I want to use HTML to display the help text. There is also another view controller which is kind of the "main" VC. There is a "Present as Popover" segue connecting the two.
From the IB, I see this:
I have an unwind segue that unwinds to the main VC. It will be triggered if the user taps the "Done" button.
And here is my code:
import UIKit
class HelpViewController: UIViewController {
#IBOutlet var webView: UIWebView!
override func viewDidLoad() {
automaticallyAdjustsScrollViewInsets = false
let htmlString = "You don't need to know about this."
webView.loadHTMLString(htmlString, baseURL: nil)
}
#IBAction func doneClicked(sender: UIBarButtonItem) {
performSegueWithIdentifier("exitToMain", sender: self)
}
}
And the unwind segues are working perfectly but the navigation bar is somehow very dark in colour!
I don't know what's happening here. I checked out this question
iOS 7 SDK - UI Navigation Bar is sometimes darker and sometimes not. But why?
The asker said that's because of a piece of code that he wrote but I swear I didn't use the same code as he did (from my limited obj-c to swift translation knowledge)!
Anyway, here is the relevant storyboard hierarchy thingy:
What causes this problem and how to fix it?
I solved the problem by setting the background colour of the UIWebView to white. And the navigation bar turns white!
I found this by observing how the colour changes when I scroll the web view up and down. I saw that initially it is kinda grey. But when I scrolled down to the white part of the web view, it changes to white. I deduced that the grey colour is actually the web view's background property and the navigation bar is kind of translucent.
And that's why setting the background colour to white fixes this issue.
Stretch the web view through the bottom of the navigation bar and set automaticallyAdjustScrollviewInsets to true. That would adjust the scroll view inset to show the content at the right content.
did you try this
self.navigationController!.navigationBar.translucent = true

Two UIViewControllers inside UIScrollView - resigning first responder

In the app I am working on I have two view controllers inside a scroll view. The second view controller (VC2) contains a text view. You can see the setup on the image below:
!
When I scroll from VC2 to VC1, the keyboard persists and covers the content of VC1. I managed to solve the problem by making the scroll view the first responder on scrollViewDidScroll event. This works, but it results in the keyboard disappearing even on a partial scroll, which can be annoying to the users. I can solve this problem by also checking the content offset but it strikes me as overcomplicated and not elegant at all. Is there a better way to do this?
Edit:
As Chonch and latenitecoder suggested, I detected the page change. I adapted the code from: Detecting UIScrollView page change to swift. Here it is:
var previousPage = 0
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let pageWidth = scrollView.frame.size.width
let fractionalPage = scrollView.contentOffset.x / pageWidth
let page = Int(round(fractionalPage))
if (previousPage != page) {
// Page has changed, do your thing!
self.becomeFirstResponder()
// Finally, update previous page
previousPage = page
}
}
You can set the UIScrollView's pagingEnabled property to YES and only call resignFirstResponder for the UITextView when the paging ended and the resulting page is VC1. As long as the current page remains VC2, you don't call resignFirstResponder, and the keyboard remains shown.
However, notice that it may actually be a good idea to hide the keyboard as soon as the user starts scrolling (as you're describing is your current state). Maybe you should leave it like this and when the paging ends, check if the current page is VC2, and if it is, call becomeFirstResponder on the UITextView in order to display the keyboard again.
I'd suggested to use UIPageViewController to horizontal scrolling controllers. Then you can do the same action in it's delegate method
- (void)pageViewController: didFinishAnimating: previousViewControllers: transitionCompleted: but it will save you memory a lot.

Embedding subview in main view Swift

If you look at this image (I don't want to upload it, as it does not belong to me), you will see what appears to be a uiview inside the main uiview controller in the settings app of an iPad. My question is, how do I replicate this programatically? In other words, how do I embed a UIView in another?
Here's what I know and have done:
Based on my research, this is called "subviews". Is this correct?
I have created a UIView with the proper elements that I want in interface builder. It is currently not a subview, but at the same level hierarchically as my main view.
I found the same exact question except in Obj-C, not my language (Swift).
Here's what I need:
How do I programatically spawn a subview in swift once a button is clicked?
As this subview is pretty complex in terms of UIelements, I want to be able to design it in interface builder.
Here's what I have so far:
#IBAction func buttonPressedSpawnSubview(sender: AnyObject) {
//Open a subview from Interface builder.
}
#IBAction func closeButtonPressedSpawnSubview(sender: AnyObject) {
//kill the subview.
Can someone help me figure out how fill in the commented lines?
What you are seeing is a modal UIView on top of another view.
An example from within your visible ViewController would be:
self.modalTransitionStyle = UIModalTransitionStyle.FlipHorizontal // Choose whatever transition you want
self.modalPresentationStyle = .CurrentContext // Display on top of current UIView
self.presentViewController(yourNewViewObject, animated: true, completion: nil)

Resources