I have a UIScrollView with a UIView inside of it. When I try to manually resize the UIView by code, it doesn't work. I tried to set the autoResizingMask property of the UIView to .None and I implemented the touchesShouldCancelInContentView method of the UIScrollView to return true but it still doesn't work. Here's my code :
class ViewController: UIViewController {
#IBOutlet var scrollView: CustomScrollView!
#IBOutlet var field: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
var gesture = UITapGestureRecognizer(target: self, action: "gestureHandler")
gesture.numberOfTapsRequired = 1
view.addGestureRecognizer(gesture)
scrollView.contentSize = CGSizeMake(430, 140)
field.autoresizingMask = .None
}
func gestureHandler() {
field.frame.size.width += 20
var view = UIView(frame: CGRectMake(0, 0, 30, 100))
view.backgroundColor = UIColor.redColor()
field.frame.size.width -= 30
field.frame.origin.x += 30
scrollView.addSubview(view)
}
}
class CustomScrollView: UIScrollView {
override func touchesShouldCancelInContentView(view: UIView!) -> Bool {
return true
}
}
What I get :
What I want :
Thanks for your help !
Related
I created a new file with the following class:
import Foundation
import UIKit
var Feld = classFeld()
class classFeld {
let button = UIButton()
func createButton() -> UIButton {
button.frame = CGRect(x: 10, y: 50, width: 200, height: 100)
button.backgroundColor=UIColor.black
button.addTarget(self, action: #selector(ButtonPressed(sender:)), for: .touchUpInside)
return button
}
#objc func ButtonPressed(sender: UIButton!) {
button.backgroundColor=UIColor.red
}
}
And this is my ViewController:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
mainview.addSubview(Feld.createButton())
self.view.addSubview(mainview)
}
var mainview=UIView()
}
When I start the app a black button is created but when I click on it it doesnt color red.
If I add the button instead of
mainview.addSubview(Feld.createButton())
to
self.view.addSubview(Feld.createButton())
it works and the button turns red.
May I anyone explain me why? It should make no difference if I add something to self.view or to a subview which is then added to self.view?
Because you need to give it a frame and add it to self.view
var mainview = UIView()
This is because you are just initializing a UIView without giving it any frame and adding it to the main view.
You need to give frame to your mainview also. For example :
class ViewController: UIViewController {
var mainview = UIView()
override func viewDidLoad() {
super.viewDidLoad()
mainview.frame = CGRect(x: 10, y: 50, width: 300, height: 300)
self.view.addSubview(mainview)
mainview.addSubview(Feld.createButton())
}
}
Here is changes on ViewController class and working fine:
class ViewController: UIViewController {
var mainview: UIView!
override func viewDidLoad() {
super.viewDidLoad()
mainview = UIView(frame: self.view.bounds)
mainview.addSubview(Feld.createButton())
self.view.addSubview(mainview)
}
}
I have a class called BaseViewController which contains a function where I can add a header to my VC and anchor it
class BaseViewController: UIViewController {
let headerView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.green
return view
}()
func addHeader() {
view.addSubview(headerView)
// then anchor it to top
}
}
I have another class called ScrollViewController which adds a scrollViewController to my VC and anchors it
class ScrollViewController: UIViewController {
let scrollView: UIScrollView = {
let view = UIScrollView()
view.backgroundColor = UIColor.green
return view
}()
func addScrollView() {
view.addSubview(scrollView)
// then anchor it to top
}
}
Finally my main class HomeViewController wants to have both a header and a scrollView so I inherit from both like this:
class HomeViewController: ScrollViewController, BaseViewController {
override viewDidLoad() {
super.viewDidLoad()
addScrollView()
addHeaderView()
let view = UIView()
//anchor view to bottom of the header
}
}
However swift doesn't allow multiple inheritance so I tried using protocols and extensions which works but the problem is that I want other views to be able to be anchored to the header and scrollView so it didn't fit my needs.
What could I do so I can implement something like that
Thanks
Swift does not support multiple inheritance. However, protocols and protocol extensions can accomplish what you want.
Example:
protocol HeaderProtocol {
func addHeaderView() -> UIView
}
extension HeaderProtocol where Self: UIViewController {
func addHeaderView() -> UIView {
let headerView = UIView()
headerView.backgroundColor = UIColor.green
view.addSubview(headerView)
// then anchor it to top
return headerView
}
}
protocol ScrollViewProtocol {
func addScrollView() -> UIView
}
extension ScrollViewProtocol where Self: UIViewController {
func addScrollView() -> UIView {
let scrollView = UIScrollView()
scrollView.backgroundColor = UIColor.green
view.addSubview(scrollView)
// then anchor it to top
return scrollView
}
}
class HomeViewController: UIViewController, ScrollViewProtocol, HeaderProtocol {
override func viewDidLoad() {
super.viewDidLoad()
let scrollView = addScrollView()
let headerView = addHeaderView()
}
}
Alternative approach:
protocol HeaderProtocol {
var headerView: UIView? { get set }
func addHeaderView() -> UIView
}
extension HeaderProtocol where Self: UIViewController {
func addHeaderView() -> UIView {
let headerView = UIView()
headerView.backgroundColor = UIColor.green
view.addSubview(headerView)
// then anchor it to top
return headerView
}
}
protocol ScrollViewProtocol {
var scrollView: UIView? { get set }
func addScrollView() -> UIView
}
extension ScrollViewProtocol where Self: UIViewController {
func addScrollView() -> UIView {
let scrollView = UIScrollView()
scrollView.backgroundColor = UIColor.green
view.addSubview(scrollView)
// then anchor it to top
return scrollView
}
}
class HomeViewController: UIViewController, ScrollViewProtocol, HeaderProtocol {
var scrollView: UIView?
var headerView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
scrollView = addScrollView()
headerView = addHeaderView()
}
}
This is driving me nuts!
I'm basing my UIScrollView on http://koreyhinton.com/blog/uiscrollview-crud.html to make it programatic, so have set up a container view inside my scrollview. But it pans, but won't zoom.
class BinaryTreeViewController: UIViewController, UIScrollViewDelegate {
var scrollView: UIScrollView!
var containerView : UIView!
override func viewDidLoad() {
super.viewDidLoad()
let width:CGFloat = self.view.bounds.width
let height:CGFloat = self.view.bounds.height
scrollView = UIScrollView()
scrollView.delegate = self
scrollView.minimumZoomScale = 0.5
scrollView.maximumZoomScale = 2.0
scrollView.contentSize = CGSize(width: width*2, height: 2000)
scrollView.backgroundColor = .red
containerView = UIView()
scrollView.addSubview(containerView)
view.addSubview(scrollView)
containerView.isUserInteractionEnabled = true
scrollView.isUserInteractionEnabled = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.frame = view.bounds
containerView.frame = CGRect(x: 0, y: 0, width: scrollView.contentSize.width, height: scrollView.contentSize.height)
}
override func viewWillLayoutSubviews() {
//I create a view called "theView"
containerView.addSubview(theView)
}
The following functions do not fire at any point
func update(zoomScale: CGFloat, offSet: CGPoint) {
scrollView.zoomScale = zoomScale
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return containerView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
NSLog("scroll")
}
You really don't need to do so much code for that purpose.
You can set up all you need for scrollView in storyboard, and you only need outlet for the view you wish to zoom.
Set up a controller, add scrollview, connect delegate property to view controller, add zooming view as subview in IB.
In the class, conform controller to UIScrollViewDelegate, and use viewForZooming, a scrollView delegate method.
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var zoomer: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return zoomer
}
}
P.S. Use newer resources for learning, Ray Wenderlich, AppCoda, etc - its a big web full of good sources, and Swift is in constant change.
When I instantiate and add a scroll view to my self.view in my ViewController class and set the scroll view's delegate to self, the delegate functions get called. As written below:
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var smallView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let width = Double(view.frame.width)
let height = Double(view.frame.height)
let frame = CGRect(x: 0.0, y: 0.0, width: width, height: height)
let scrollView = UIScrollView(frame: frame)
//scrollView.backgroundColor = UIColor.blue
let size = CGSize(width: width + 300, height:1000)
scrollView.contentSize = size
smallView.addSubview(scrollView)
scrollView.delegate = self
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("Gets called.")
}
}
However, when I create a custom class, in this case called, PhotoBooth, and call try to call the delegate function in this custom class, the functions do not get called. Here is my custom class:
import Foundation
import UIKit
class PhotoBooth: NSObject, UIScrollViewDelegate {
private var boothView: UIView
//private var scrollView: UIScrollView
init(view: UIView) {
boothView = view
}
func startSession() {
let width = Double(boothView.frame.width)
let height = Double(boothView.frame.height)
let frame = CGRect(x: 0.0, y: 0.0, width: width, height: height)
let scrollView = UIScrollView(frame: frame)
//scrollView.backgroundColor = UIColor.blue
let size = CGSize(width: width + 300, height:1000)
scrollView.contentSize = size
boothView.addSubview(scrollView)
scrollView.delegate = self
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("paisdjfij")
}
}
And I instantiate the class in my ViewController like so:
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var smallView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let photoBooth = PhotoBooth(view: self.view)
photoBooth.startSession()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Any solutions to the problem? Please let me know and thank you so much for your help in advance.
Instead of trying this You should use protocols to call scroll view in custom class.It will look somewhat like this.
CustomClass.h
#protocol CustomDelegate <NSObject>
-(void)customDelegateMethod;
#end
#interface CustomClass : UIScrollView <UIScrollViewDelegate>
{
id<CustomDelegate> delegate
}
CustomClass.m
-(void) methodScrollView
{
[self.delegate customDelegateMethod];
}
ViewController.h
#interface ViewController: UIViewController <CustomDelegate>
{
}
ViewController.m
-(void)makeCustomScrollView
{
CustomClass *objCustom = [[CustomClass alloc] init];
objCustom.delegate = self;
//other stuff
}
-(void)customDelegateMethod
{
}
I am trying to get the scrollview of a uitableview that is static to get updated, I have a container view that will change sizes, and that works, but i cannot get the scrollable area to update.
I have tried setNeedsDisplay and setNeedsLayout and no luck.
Any ideas?
class TimeAwayRequestTableViewController: UITableViewController {
var originalHeight : CGFloat!
#IBOutlet var selectedDate : UIView!
#IBOutlet var calendarView: CalendarView!
override func viewDidLoad() {
super.viewDidLoad()
originalHeight = self.tableView.contentSize.height
calendarView.delegate = self
self.selectedDate.frame.size.height = CGFloat(SelectedDatesTimeAway.selectedDates.count * 44)
}
override func preferredContentSizeDidChangeForChildContentContainer(container: UIContentContainer) {
self.selectedDate.frame.size.height = CGFloat(SelectedDatesTimeAway.selectedDates.count * 44)
self.tableView.contentSize.height = self.originalHeight + self.selectedDate.frame.size.height
self.tableView.setNeedsDisplay()
self.tableView.setNeedsLayout()
}
}
extension TimeAwayRequestTableViewController : CalendarViewDelegate {
func calendarDidSelectDate(date: Moment) {
let theDate = date.date
SelectedDatesTimeAway.selectedDates.append(theDate)
print(SelectedDatesTimeAway.selectedDates.count)
let tbc = self.childViewControllers[0] as! UITableViewController
tbc.preferredContentSize.height = CGFloat ( SelectedDatesTimeAway.selectedDates.count * 44 )
print(tbc.preferredContentSize.height)
tbc.tableView.reloadData()
}
func calendarDidPageToDate(date: Moment) {
print(date)
}
}
If I understand the nature of your problem, you need to update the contentSize property of your UIScrollView when you change the content.