I am using project from github as a reference.
project URL:
https://github.com/lephuocdai/iOSsample/tree/master/PageViewDemo
In this project i want to show the UIPageControl at top left position .
I tried setting the rect property of pageControl using CGRectMake() to some value ;But it shows always at bottom center
here s a very neat and 100% effective way to get to change the position of the pageControl
extension UIPageViewController {
override open func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for subV in self.view.subviews {
if type(of: subV).description() == "UIPageControl" {
let pos = CGPoint(x: newX, y: newY)
subV.frame = CGRect(origin: pos, size: subV.frame.size)
}
}
}
}
The project uses a UIPageViewController to handle the display and movement through the content.
You can supply data to that object so it displays a UIPageControl as you say.
BUT you have no control over the display of that item, other than maybe some colour styling.
If you want to position it, you'll need to implement you're own instance of UIPageControl and handle it's content, position and changes manually.
Override the viewDidLayoutSubviews() of the pageviewcontroller and use this
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// get pageControl and scroll view from view's subviews
let pageControl = view.subviews.filter{ $0 is UIPageControl }.first! as! UIPageControl
let scrollView = view.subviews.filter{ $0 is UIScrollView }.first! as! UIScrollView
// remove all constraint from view that are tied to pagecontrol
let const = view.constraints.filter { $0.firstItem as? NSObject == pageControl || $0.secondItem as? NSObject == pageControl }
view.removeConstraints(const)
// customize pagecontroll
pageControl.translatesAutoresizingMaskIntoConstraints = false
pageControl.addConstraint(pageControl.heightAnchor.constraintEqualToConstant(35))
pageControl.backgroundColor = view.backgroundColor
// create constraints for pagecontrol
let leading = pageControl.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor)
let trailing = pageControl.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor)
let bottom = pageControl.bottomAnchor.constraintEqualToAnchor(scrollView.topAnchor, constant:8) // add to scrollview not view
// pagecontrol constraint to view
view.addConstraints([leading, trailing, bottom])
view.bounds.origin.y -= pageControl.bounds.maxY
}
is your page control encompassed within some other View, if so then you may be setting the co-ordinates wrong, try to put log of your page control.frame so as to know where it lies
If using storyboards, place a UIPageControl object using the menu in the bottom right and set constraints.
If using frames, just programmatically add it:
var pageControl = UIPageControl()
pageControl.frame = CGRectMake(0,0,0,0) <- These are the coordinates.
self.view.addSubView(pageControl)
if you set the frame for UIPageControl , it doesnot work.
Other than this you can set the transform.
[_pageControl setTransform:CGAffineTransformMakeTranslation(100, 0.0)];
enjoy coding
Related
I'm trying to use a custom view as an accessory view over the keyboard, for various reasons, in this case, it is much preferred over manual keyboard aligning because of some other features.
Unfortunately, this is a dynamic view that defines its own height. The constraints all work fine outside of the context of an accessoryView without errors, and properly resizing
When added as a keyboardAccessoryView it seems to impose a height of whatever the frame is at the time and break other height constraints
It appears as:
"<NSLayoutConstraint:0x600003e682d0 '_UIKBAutolayoutHeightConstraint' Turntable.ChatInput:0x7fb629c15050.height == 0 (active)>"
(where 0 would correspond to whatever height had been used at initialization
It is also labeled accessoryHeight which should make it easy to remove, but unfortunately, before I can do this, I'm getting unsatisfiable constraints and the system is tossing my height constraints
Tried:
in the inputAccessoryView override, I tried to check for the constraints and remove it, but it doesn't exist at this time
setting translatesAutoresizing...Constraints = false
tl;dr
Using a view as a KeyboardAccessoryView is adding its own height constraint after the fact, can I remove this?
Looks like keyboard doesn't like inputAccessoryView with height constraint. However you still can have inputAccessoryView with dynamic height by using frame (it is still possible to use constraints inside your custom inputAccessoryView).
Please check this example:
import UIKit
final class ViewController: UIViewController {
private let textField: UITextField = {
let view = UITextField()
view.frame = .init(x: 100, y: 100, width: 200, height: 40)
view.borderStyle = .line
return view
}()
private let customView: UIView = {
let view = UIView()
view.backgroundColor = .red
view.frame.size.height = 100
view.autoresizingMask = .flexibleHeight // without this line height won't change
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(textField)
textField.inputAccessoryView = customView
textField.becomeFirstResponder()
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.customView.frame.size.height = 50
self.textField.reloadInputViews()
}
}
}
I have a "classic app" with 3 ViewController and a tabBar that I use to change ViewController.
On my first ViewController, I have a button that display a UIView on all the screen, so I hide tabBar with this setTabBarVisible func :
extension UIViewController
{
func setTabBarVisible(visible: Bool, animated: Bool)
{
//* This cannot be called before viewDidLayoutSubviews(), because the frame is not set before this time
// bail if the current state matches the desired state
if (isTabBarVisible == visible) { return }
// get a frame calculation ready
let frame = self.tabBarController?.tabBar.frame
let height = frame?.size.height
let offsetY = (visible ? -height! : height)
// zero duration means no animation
let duration: TimeInterval = (animated ? 0.3 : 0.0)
// animate the tabBar
if frame != nil
{
UIView.animate(withDuration: duration)
{
self.tabBarController?.tabBar.frame = frame!.offsetBy(dx: 0, dy: offsetY!)
return
}
}
}
var isTabBarVisible: Bool
{
return (self.tabBarController?.tabBar.frame.origin.y ?? 0) < self.view.frame.maxY
}
}
That's working, the tabBar is hidden and I see all my UIVIew.
The problem is, I have a UILabel at bottom of the UIView (at the place I usually display the tabBar), and I can't use my TapGesture on my UILabel, nothing is happening.
(if I display the label somewhere else the UITapGesture works good.)
I tried to set zPosition of my tabBar to 0 and zPosition of my UIView to 1 but that's doesn't work either.
How can I get my label clickable at bottom of my view?
Check UILabel.isUserInterration = enable
Make sure that when you hide tabbar, perticular view controller Under bottom bar property is unselect . See atteh imnage.
You can try with programatically also like
ViewController.edgesForExtendedLayout = UIRectEdge.top
make sure is true
label.isUserInteractionEnabled = true
Please refer this link may it help you.
Please refer to this Answer.
I am trying to do the same thing, however I want to do this in a Tab Bar App where the Now Playing bar is above the Tab Bar in all the scenes of the app.
Update:
I want to have a view at the bottom of the screen (above the tab bar) and under the content views of the different tabs (not above them). In addition, I want to have the ability to remove this view at a certain point making the main view take the whole screen.
I can do this using the mentioned Answer by changing the constraints of the nowPlaying view programmatically.
Using UITabBarViewController subclass it is possible:
Ex:
class DashBoardViewController: UITabBarController {
let nowPlayingBar:UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = .blue
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
initView()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
nowPlayingBar.frame = tabBar.frame
}
override func viewDidAppear(_ animated: Bool) {
var newSafeArea = UIEdgeInsets()
// Adjust the safe area to accommodate
// the height of the bottom views.
newSafeArea.bottom += nowPlayingBar.bounds.size.height
// Adjust the safe area insets of the
// embedded child view controller.
self.childViewControllers.forEach({$0.additionalSafeAreaInsets = newSafeArea})
}
private func initView() {
nowPlayingBar.frame = tabBar.frame
view.addSubview(nowPlayingBar)
}
}
You'll add your view/container to your app window, you'd do something like
guard let window = (UIApplication.shared.delegate as? AppDelegate)?.window
else { return } // check if there's a window
let containerHeight: CGFloat = 50 // height for the view where you wish to add the music player
let containerFrame = CGRect(x:0, y: window.frame.maxY - (tabBar.frame.height + containerHeight), width: window.frame.width, height: containerHeight)
// most important part here is the y axis in some sense, you will add the height of the tabBar and the container, then subtract it from window.frame.maxY
let container = UIView(frame: containerFrame)
// now you have the container do whatever you want with it
window.addSubView(container) // finally add the container to window as a subview
I seem to be having some issues getting the UIPageControl to work.
I have a ViewController that holds a ScrollView. This ScrollView loads nib files that can be swiped. See image:
Here is the code that loads these:
self.addChildViewController(vc0)
self.displayReportView.addSubview(vc0.view)
vc0.didMoveToParentViewController(self)
var frame1 = vc1.view.frame
frame1.origin.x = self.view.frame.size.width
vc1.view.frame = frame1
self.addChildViewController(vc1)
self.displayReportView.addSubview(vc1.view)
vc1.didMoveToParentViewController(self)
// And so on
...
This works fine as in they scroll correctly etc..
Now, on the ViewController (one holding the scrollview) I added the delegate:
UIScrollViewDelegate
created some variables:
var frame: CGRect = CGRectMake(0, 0, 0, 0)
var colors:[UIColor] = [UIColor.redColor(), UIColor.blueColor(), UIColor.greenColor(), UIColor.yellowColor()]
var pageControl : UIPageControl = UIPageControl(frame: CGRectMake(50, 300, 200, 20))
I added some functions that are needed:
func configurePageControl() {
// The total number of pages that are available is based on how many available colors we have.
self.pageControl.numberOfPages = 4
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.redColor()
self.pageControl.pageIndicatorTintColor = UIColor.blackColor()
self.pageControl.currentPageIndicatorTintColor = UIColor.greenColor()
self.view.addSubview(pageControl)
}
// MARK : TO CHANGE WHILE CLICKING ON PAGE CONTROL
func changePage(sender: AnyObject) -> () {
let x = CGFloat(pageControl.currentPage) * displayReportView.frame.size.width
displayReportView.setContentOffset(CGPointMake(x, 0), animated: true)
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
pageControl.currentPage = Int(pageNumber)
}
Now, When I run the app the scrollview dots show, but when I swipe they do not update.
Question
How do I update the dots to reflect what view is showing?
let me know if you need anything else from my code to see functionality.
You can certainly do what you're describing, if you have a paging scroll view; I have an example of it that uses this code:
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let x = scrollView.contentOffset.x
let w = scrollView.bounds.size.width
pageControl.currentPage = Int(x/w)
}
Except for your round, that looks a lot your code, which makes me think that your code should work. That makes me think that something else is just misconfigured. Is this a paging scroll view? Did you remember to make this object your scroll view's delegate? Use logging or a breakpoint to be certain that your scrollViewDidEndDecelerating is even being called in the first place.
However, I would just like to point out that the configuration you are describing is effectively what UIPageViewController gives you for free — a scroll view with view controller views, plus a page control — so you might want to use that instead.
I would replace the scroll view with a UICollectionView. This way you get paging for free, and it will be better, because paging will work out of the box, without you having to calculate the frame offsets.
Be sure to set collectionView.pagingEnabled = true
To get the current page number, do collectionView.indexPathsForVisibleItems().first?.item
To change the page:
collectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: CenteredHorizontally, animated: true)
I have created a view, CustomView.xib, and a dedicated class, CustomView.swift. I have added it to my ViewController in Storyboard by adding a view and setting the custom class to CustomView.swift and it works perfectly. The constraints I added in StoryBoard resize the nib like I want. Now I want to create copies of it, like cells/rows in a tableView (like a twitterfeed). How can I do that, while maintaining the constraints so that it resize correctly? I guess my question boils down to: How do you duplicate UIViews created in StoryBoard? I realise that the top constraint might have to be altered as row's are added. And second, since this is a nib, how can I change the label within it? The project is on GitHub
Any help would be very much appreciated! Thank you.
import UIKit
class ScrollViewController: UIViewController {
let scrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
let height = CGFloat(200.0)
self.scrollView.frame = self.view.bounds
self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, height*3)
self.view.addSubview(self.scrollView)
var y = CGFloat(0.0)
for i in 0..<2 {
//DO I ADD IBOUTLET(s)?
// How do I set width of frame to the View in StoryBoard (that has constraints?
//Do I tag it, give it an ID - How can I create copies of the customView from StoryBoard
let customView = CustomView(frame: CGRectMake(0, y, 320, 200))
self.scrollView.addSubview(customView)
y += height
}
}
func createCustomView(index: Int) -> UIView {
//How do I instantiate the view here without setting the frame size?
let customView = CustomView(frame: CGRectMake(0, 0, 320, 200))
if index == 0{
customView.backgroundColor = UIColor.greenColor()
//How do I change the label text, like below?
//customView.label.text = "New York"
}
if index == 1{
customView.backgroundColor = UIColor.redColor()
//How do I change the label text, like below?
//customView.label.text = "Tokyo"
}
return customView
}
}