Segmented Control Subview from extension - ios

I'm trying to add a subview below my UISegmentedControl from an extension so when I add more properties to this subview it can be reused from other UISegmentedControls within the app.
It appears in the right place, but for some reason sometimes appears above some segments and sometimes below. Am I missing something?
So far in my extension, that's what I have:
import UIKit
extension UISegmentedControl {
func addBackgroundView() {
let backgroundView = UIView();
backgroundView.frame = self.bounds;
backgroundView.backgroundColor = UIColor.purple;
self.insertSubview(backgroundView, belowSubview: self);
}
}
And then, I call the extensions function from the viewDidLoad method in the ViewController:
self.segmentedControlUnit.addBackgroundView();

I dont think you can do this. this is the UI Hierarchy when i select 2nd segment ,
and this is the UI Hierarchy when i select 3rd segment
so the segment position changes depending on what segment you select.

Try to insert backgroundView at index 0 to make sure it below all of subview
self.insertSubview(backgroundView, at: 0)

Related

Fitting a UIScrollView to a UIView

I am trying to use a UIScrollView to show a series of UIViews. In my storyboard I have a View Controller containing a UIView that is constrained using AutoLayout.
View Controller (UIView in grey)
In order to call the UIScrollView I am using the following method:
func initScrollview() {
self.mainScrollView = UIScrollView(frame: self.mainView.bounds)
self.mainScrollView!.contentSize = CGSizeMake((self.mainView.bounds.width)*CGFloat(3), self.mainView.frame.height)
self.mainScrollView!.backgroundColor = UIColor.greenColor() // For visualization of the UIScrollView
self.mainScrollView!.pagingEnabled = true
self.mainScrollView!.maximumZoomScale = 1.0
self.mainScrollView!.minimumZoomScale = 1.0
self.mainScrollView!.bounces = false
self.mainScrollView!.showsHorizontalScrollIndicator = true;
self.mainScrollView!.showsVerticalScrollIndicator = false;
self.mainScrollView!.delegate = self
for i in 0...3 {
var tempView = SubView(frame: self.mainView.bounds)
pages.insert(tempView, atIndex: i)
self.mainScrollView!.addSubview(pages[i]);
}
self.mainScrollView!.scrollRectToVisible(CGRectMake(mainScrollView!.frame.size.width, 0, mainScrollView!.frame.size.width, mainScrollView!.frame.size.height), animated: false)
}
When I run my code, the UIScrollView does not fit the UIView. Instead it is too short and too wide. The result looks like this:
UIView in grey, UIScrollView in green
What am I doing wrong that is causing the UIScrollView to be incorrectly sized?
You should put the codes that you init the UI element sizes base on the screen size(UIView of UIViewController) in viewDidLayoutSubviews. Because in viewDidLoad, the screen didn't adjust its size yet,
In the above code, there no mention of adding the mainScrollView to the mainVew.
To whose view are you adding the mainScrollView? My opinion would be you are trying to add it to self.view whereas it should be to self.mainView
After the initScrollView() function is called try adding it the below code
self.mainView.addSubview(mainScrollView!)
This would probably be easier if you had placed all these views directly in your storyboard instead of programatically. I don't see anything in your code that can't be done visually in IB. Also, if you have autoLayout active in your storyboard, setting frames and sizes in code won't work. (auto-layout will change your values on the next pass)

adding a uipageviewcontroller to a uistackview

I'm trying to add a sliding photo gallery functionality to the top portion of a view.
To give context, a user taps on a button or row or something. Then i load a scrollview with a uistackview in it. organized vertically, i had an image, and then another stack view with some text in it. Now, i want that image to become part of a larger "gallery". My research told me to implement UIPageviewcontroller and add the other images to a childVC.
i used this as a tutorial (the first example): http://www.raywenderlich.com/76436/use-uiscrollview-scroll-zoom-content-swift
the only relevant deviation from the tutorial my app has is that it creates things programmatically.
With my proof of concept for the gallery functionality, i wanted to integrate it with the previously mentioned stack view. my plan was to first add the pageviewcontroller stuff into the overall stack view with the original image view right below it and then simply remove the original image view to leave me the final product.
i was able to add the pageviewcontroller.view to the stackview, but the gallery doesn't show. taking a look at the UI Inspector, i can see that the gallery is kinda loaded, but it's messed up.
it's as if the uiview has a frame of 0 height and so the other stack view items don't respect the images that the pageviewcontroller is trying to show.
I think it could be that stack views can only handle specific views, not stuff as complicated as pageviewcontrollers.
also note: my implementation is all programmatic, no storyboards, and so for no xibs. so maybe i missed something here.
here is some code, if it helps:
note the constrain functions you see are from the "cartography" pod
this adds the "gallery" to the stack view, it's a delegate function from my view
func addZoomStuff(sender: UIStackView) {
let zoomer = PageBaseViewController()
addChildViewController(zoomer)
zoomer.view.translatesAutoresizingMaskIntoConstraints = false
zoomer.view.tag = 5
sender.addArrangedSubview(zoomer.view)
zoomer.didMoveToParentViewController(self)
}
this is what creates the scrollview, image view, etc for the gallery items:
override func viewDidLoad() {
super.viewDidLoad()
//MARK: - Zoom View Elements
// prep
scrollView = UIScrollView(frame: self.view.frame)
scrollView.delegate = self
self.view.addSubview(scrollView)
constrain(scrollView, view) { view, view2 in
view.edges == view2.edges
}
self.view.setNeedsUpdateConstraints()
// 1
let image = UIImage(named: imageName)!
imageView = UIImageView(image: image)
// 2
scrollView.addSubview(imageView)
constrain(imageView){ view in
view.edges == view.superview!.edges
}
scrollView.contentSize = image.size
i tried adding the constraints like this but there was no effect
func addZoomStuff(sender: UIStackView) {
let zoomer = PageBaseViewController()
addChildViewController(zoomer)
view.addSubview(zoomer.view)
constrain(zoomer.view, view) { view, view2 in
view.width == view2.width
view.height == view2.height * 2 / 3
view.leading == view2.leading
view.top == view2.top
}
zoomer.view.setNeedsUpdateConstraints()
zoomer.view.removeFromSuperview()
zoomer.view.translatesAutoresizingMaskIntoConstraints = false
zoomer.view.tag = 5
print("sender.subviews: \(sender.subviews)")
sender.addArrangedSubview(zoomer.view)
zoomer.didMoveToParentViewController(self)
print("sender.subviews: \(sender.subviews)")
}
if this method isn't going to work, can i do a nested horizontal stack view instead of the pageviewcontroller and somehow get that same scrolling/snap effect to see on image view at a time?
TLDR;
Create a subclass of UIPageViewController, make it it's own delegate.
Initialize the subclass with a plain UIViewController, only set a backgroundcolor.
In the pageviewcontroller subclass, implement the two delegate callbacks for a next and previous viewcontroller: create a plain viewcontrolller, with some random backgroundcolor.
If this works, replace the plain viewcontroller by your actual contentviewcontroller.
Long version:
Have you seen this: Maybe this link will help: https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/PageViewControllers.html
It might help, as it explains the details of UIPageViewController. Basically, you need to create a viewController (not a view!), that shows one page of the gallery. So this VC has a stackview, and manages the content of it. The pageviewcontroller is initialized with your first contentviewController. If you create a subclass of the uipageviewcontroller, you can set self of that subclass as the delegate of it. Implement the delegate callbacks that return the next or previous viewController and thats it. For this last part, it is convenient to have a property on the contentviewcontroller from which the subclasses of the pageviewcontroller can figure out what data to set on the next or previousviewcontroller.
Your title seeks to hint at some confusion: its not possible to add a viewcontroller to a view. You can only add other views to a (stack)view. A viewcontroller owns and manages a viewhierarchy. A pageviewcontroller has no content, but manages the insertion and removal of viewcontrollers. as the pageviewcontroller is a containerviewcontroller, it will als take the contentViewcontrollers' views and place them in the viewhierarchy. But this is not something your code has to do when you subclass UIPageViewControlller and implement it's delegates on itself (and don't forget to assign self to be the delegate).

How to SubView a ViewController into a SubView of another ViewController

I have two ViewController.
One ViewControllers contain a UITableView. And another contains a UIButton.
I have created a SubView Programmatically.Now i want to SubView the ViewController which contains the UITableView in other when i Press UIButton.
I searched all over the net but cannot find any stable solution.
Currently i am trying this:
bodyView =[[UIView alloc]initWithFrame:CGRectMake(0,120,containerView.frame.size.width,120)];
bodyView.backgroundColor = [UIColor redColor];
CustomTableVC *tableVC = [[CustomTableVC alloc]init];
[tableVC willMoveToParentViewController:self];
[bodyView addSubview:tableVC.view];
[self addChildViewController:tableVC];
[tableVC didMoveToParentViewController:self];
[containerView addSubview:bodyView];
You cannot.
You can only use the view property of your UIViewController to assign into UIView associated in your second UIViewController which is not recommended because UIViewController as per MVC pattern holds lot controller stuff which includes populating the view and resolving the inputs/touch, which is an overhead in your (using multiple of viewcontrollers without needed) case.
You need to use one UIViewController. Add UITableView only in it, and UIButton only in it. You only use one controller and multiple views.
The other approach, if you do not want to change your code, may also use ContainerView. But in that case you need to create separate ViewControllers for UIButton and UITableView. And if you want to fetch data inbetween the ViewControllers, that will be a huge pain and also a bad software design with so much coupling and less encapsulation.
i have tried this one and it's working for me.
#IBAction func moveToOther() {
var otherController = OtherViewController()
var bodyView = UIView(frame: CGRectMake(0,120, self.view.frame.size.width, 120))
bodyView.backgroundColor = UIColor.redColor();
bodyView.layer.borderWidth = 1.0
let tblCntrl = UITableViewController()
bodyView.addSubview(tblCntrl.tableView)
bodyView.clipsToBounds = true
otherController.addChildViewController(tblCntrl)
tblCntrl.didMoveToParentViewController(otherController)
otherController.view.addSubview(bodyView)
self.navigationController?.pushViewController(otherController, animated: true)
}
You should use only one view controller that contains both the table view & UIButton.
By default hide the table view.
Just hide the button and show the table view when the button is clicked.

UIScrollView with UIView (Swift)

I have implemented a UIScrollView with a UIView which I add when viewDidLoad() to the UIScrollView which is set to the UIViewControllers view. When I do this how ever the frame of the UIView with the setTranslatesAutoresizingMaskIntoConstraints(false) gets set to -101.0. This does not happen to another view that is displayed differently,but only happens to this view which is designed the same, and displayed with pushViewController from the navigationController.
The constraints are setup from the NIB/XIB files and I am confused why this is occurring.
Another thing to note is that, when this happens, no matter where I try and change the frame of the UIView, it has no affect.
EDIT:
CODE for viewDidLoad():
override func viewDidLoad(){
// call the super implementation
super.viewDidLoad();
// load our scrollview from our nib file
customScrollView = CustomScrollView.loadFromNib();
// set the resizeing mask to fill screen
customScrollView!.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
// load our uiview from our nib file
containerView = ContainerView.loadFromNib();
// we handle the constraint changes
containerView!.setTranslatesAutoresizingMaskIntoConstraints(false);
customScrollView!.addSubview(containerView!);
// intialize our refresh control
refreshControl = UIRefreshControl();
refreshControl!.tintColor = UIColor.whiteColor();
refreshControl!.addTarget(self, action: "onRefresh", forControlEvents: UIControlEvents.ValueChanged);
containerView!.addSubview(refreshControl!);
// add the view to our controller here
view = customScrollView!;
}
The answer ended up being a custom tableview. If anyone else is having this problem, I highly recommend ditching UIScrollView, because it is an utter disappointment from apple. The documentation is poor, and there are technical issues with it known to be true. There are also technical document notes for some issues on the class for anyone who is trying to do something with the class, be sure to read those.

Passing y contentOffset from scrollViewDidScroll(scrollView to another view controller using swift

I am new to programming and swift.
I have a mainViewController with a containerView which contains a scrollView. I would like to be able to pass the value of the y contentOffset from this scrollView ( from the scrollViewDidScroll(scrollView function) to update the frame.origin.y of a image in the mainViewController so that it moves inrelation to the containerView's scrollView.
How can i share data between the two View controllers (or multiple view controllers) using swift?
Any help would be greatly appreciated!!!
Suppose your scroll view is named sView and UIImageView is named img.
Then you should write something like this in your ViewController:
In class declaration add comma and scroll view delegate
class ViewController: UIViewController, UIScrollViewDelegate {
Then you should implement scrollViewDidScroll function somewhere after viewDidLoad
func scrollViewDidScroll(scrollView:UIScrollView){
if scrollView == sView {
let frame = CGRectMake(img.frame.origin.x, sView.contentOffset.y, img.frame.size.width, img.frame.size.height)
img.frame = frame
println("Just check if it's called")
}}
After that add to viewDidLoad
//You've aldeady declared sView and img
self.view.addSubview(sView)
self.sView.delegate = self
Should work then :)

Resources