I started working on this App in Objective-C. Through some problems I had recently, I started using swift for some Features. Everything is working fine. Now I started building a new Feature and decided to do it in swift. I wrote the code in a Swift only Project, for testing. Everything is working fine in the test version, but when implementing it in my main Project I faced a Problem.
The Problem is that I set the view options in the delegate file like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
return true
}
But because my main Project delegate file is in Objective-C I dont know how to get this to work in my Swift file in the Objective-C Project. I tried setting the view in the viewDidLaunch file. But that doesnt work.
So i am asking myself if it is actually possible to set the code for my swift file in the Objective-C delegate method in objective-c. But for my Project I would like to set the view options inside the swift file. So this is what I tried so far:
import UIKit
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var window: UIWindow?
override func viewDidLoad() {
super.viewDidLoad()
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
navigationItem.title = "Home"
collectionView?.backgroundColor = UIColor.white
collectionView?.register(VideoCell.self, forCellWithReuseIdentifier: "cellId")
}
//number of items
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
class VideoCell: UICollectionViewCell{
override init(frame:CGRect){
super.init(frame: frame)
setupViews()
}
let thumbnailImageView: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = UIColor.blue
return imageView
}()
let userProfileImageView: UIImageView = {
let imageView = UIImageView ()
imageView.backgroundColor = UIColor.green
return imageView
}()
let separatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black
return view
}()
let titleLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.purple
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let subtitleTextView: UITextView = {
let textView = UITextView()
textView.backgroundColor = UIColor.red
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
func setupViews(){
addSubview(thumbnailImageView)
addSubview(separatorView)
addSubview(userProfileImageView)
addSubview(titleLabel)
addSubview(subtitleTextView)
//Abstand zum Bildschirmrand (Blau)
addConstraintsWithFormat(format: "H:|-16-[v0]-16-|", views: thumbnailImageView)
//Grün
addConstraintsWithFormat(format: "H:|-16-[v0(42)]", views: userProfileImageView)
//vertical constraints / v0 = Blau höhe / v1 = Grün höhe / v2 = Linie höhe
addConstraintsWithFormat(format: "V:|-32-[v0(75)]-8-[v1(44)]-16-[v2(1)]|", views: thumbnailImageView, userProfileImageView, separatorView)
//Abtrennung zwischen Zellen /zweite Zeile wird in "Große Fläche" umgesetzt
addConstraintsWithFormat(format: "H:|[v0]|", views: separatorView)
//top constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: thumbnailImageView, attribute: .bottom, multiplier: 1, constant: 8))
//left constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 1, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
//top constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .top, relatedBy: .equal, toItem: titleLabel, attribute: .bottom, multiplier: 1, constant: 4))
//left constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 1, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
thumbnailImageView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension UIView {
func addConstraintsWithFormat(format: String, views: UIView...){
var viewsDictionary = [String: UIView]()
for (index, view) in views.enumerated(){
let key = "v\(index)"
view.translatesAutoresizingMaskIntoConstraints = false
viewsDictionary[key] = view
}
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: viewsDictionary))
}
}
In general to make swift classes available in objective-c.
Also helpful for me was another question/answer on stack.
But give a thought to fundamental changes:
it may be better, to create a new app in swift and connect to the old classes via the brindging header. The documentation is really helpful.
In future, it would be easier to add new elements in swift and use new functionallity.
It's simply not safe to do this from within viewDidLoad in a view controller, and you shouldn't even attempt it.
That's because it is possible for viewDidLoad to be executed multiple times.
If that happens, it's going to replace your window and rootViewController with new instances in the middle of your app's execution (looking to the user like the app has reset itself).
You need to initialize the window and root controller from the app delegate, there's no choice.
However, you can still write most of the code in Swift.
First, create a Swift extension on UIWindow that includes a class function which initialises and configures your window, then returns it. Make sure that extension is accessible by Objective-C by adding #objc to the declaration:
#objc extension UIWindow {
class func setRootHomeViewController() -> UIWindow {
let window = UIWindow(frame: UIScreen.main.bounds)
window.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
return window;
}
}
In your Objective-C app delegate, you then need to import your Swift header and call the new UIWindow class method that you've defined. Assign the returned window object to the app delegate's window property.
#import "YourProjectName-Swift.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
_window = [UIWindow setRootHomeViewController];
return YES;
}
#end
It's only one line of Objective-C code, but it's necessary as the app delegate is the only safe place to do this.
Related
I am trying to programmatically draw my CollectionView from within a custom class that subclasses UIView. The app loads up with no errors and the CollectionView is being drawn correctly as I can see the cell items, but the CollectionView does not respond to touch. When I try to scroll nothing happens.
I inspected the ViewController using the Debug View Hierarchy button in Xcode to see if there was possibly a view on top. There was not and I could see the cells clearly drawn separately.
Class:
class DrawUI_mainCollectionView : UIView, UICollectionViewDelegate, UICollectionViewDataSource {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
var collectionView : UICollectionView?
private func setup() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: CGFloat(kScreenWidth),height: 137)
let offset = 120.0
let collectionViewFrame = CGRect(x: 0, y: offset, width: Double(kScreenWidth), height: Double(kScreenHeight))
self.collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
self.collectionView!.alwaysBounceVertical = true
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
self.collectionView!.register(UINib(nibName: "MealCategoryCell", bundle:Bundle.main), forCellWithReuseIdentifier: "cell")
self.addSubview(self.collectionView!)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MealCategoryCell
cell.label.text = "test"
cell.textDescription.text = "textDescription"
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: kScreenWidth, height: 137)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("cell \(indexPath.row)")
}
required init?(coder aDecoder: NSCoder) {
fatalError("no storyboard...")
}
}
How I am implementing it on my ViewController
let collectionView = DrawUI_mainCollectionView()
self.view.addSubview(collectionView)
What am I doing wrong? Thanks in advance.
I think your main issue is not using auto layout, if you will add auto layout for the items:
view that contains the collectionView in viewController
collectionView in the view
It should work, the implementation:
In ViewController:
let collectionView = DrawUI_mainCollectionView()
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(collectionView)
NSLayoutConstraint(item: collectionView , attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .topMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottomMargin, multiplier: 1.0, constant: 0.0).isActive = true
Inside the view:
private func setup() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: CGFloat(kScreenWidth),height: 137)
let offset = 120.0
let collectionViewFrame = CGRect(x: 0, y: offset, width: Double(kScreenWidth), height: Double(kScreenHeight))
self.collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
self.collectionView!.alwaysBounceVertical = true
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
self.collectionView!.register(UINib(nibName: "MealCategoryCell", bundle:Bundle.main), forCellWithReuseIdentifier: "cell")
self.collectionView!.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(self.collectionView!)
NSLayoutConstraint(item: collectionView , attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .top, relatedBy: .equal, toItem: self, attribute: .topMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottomMargin, multiplier: 1.0, constant: 0.0).isActive = true
}
I'm trying to add customView into headerView of my collectionView. Here's my code:
I registed the headerView class in viewDidLoad:
collectionView.register(SearchReuseView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "reuseCell")
Then I setup the collectionView:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var reuseView: UICollectionReusableView?
if indexPath.section == 0 || banners.count == 0 {
let view = UICollectionReusableView(frame: CGRect.zero)
reuseView = view
} else {
if kind == UICollectionElementKindSectionHeader {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "reuseCell", for: indexPath) as! SearchReuseView
view.backgroundColor = .black
view.delegate = self
view.frame = CGRect(x: 0, y: 0, width: collectionView.frame.width, height: 100)
view.item = banners[indexPath.section % banners.count]
return view
}
}
return reuseView!
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if section == 0 {
return CGSize.zero
}
return CGSize(width: collectionView.frame.width, height: 100)
}
But when I run on Simulator, the collectionView shows the header but nothing inside.
Here is code of SearchReuseView :
class SearchReuseView: UICollectionReusableView {
weak var delegate: SearchReuseDelegate?
let adImageView: UIImageView = {
let img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.contentMode = .scaleAspectFit
return img
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.setupViews()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.setupViews()
}
func setupViews() {
backgroundColor = .black
adImageView.isUserInteractionEnabled = true
adImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: self.adImageView, attribute: .bottom, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: self.adImageView, attribute: .right, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: self.adImageView, attribute: .top, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: self.adImageView, attribute: .left, multiplier: 1, constant: 0))
addSubview(adImageView)
}
var item: Banner! {
didSet {
guard let img = item.img else {return}
let url = URL(string: "\(img)")
self.adImageView.kf.setImage(with: url, placeholder: nil, options: [.transition(ImageTransition.fade(1))], progressBlock: { (receivedSize, totalSize) in
}) { (image, error, cacheType, imageURL) in
if error != nil {}
}
}
}
#objc func handleTap(){
guard let link = item.link else {
return
}
delegate?.didTapAds(link: link)
}
}
I wonder why your app is not crashing you should add subview first then add constraints to it
Replace your code with following code
func setupViews() {
backgroundColor = .black
addSubview(adImageView)
addSubview.translatesAutoresizingMaskIntoConstraints = false
adImageView.isUserInteractionEnabled = true
adImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: self.adImageView, attribute: .bottom, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: self.adImageView, attribute: .right, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: self.adImageView, attribute: .top, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: self.adImageView, attribute: .left, multiplier: 1, constant: 0))
}
Hope it is helpful
if kind == UICollectionElementKindSectionHeader {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "reuseCell", for: indexPath) as! SearchReuseView
view.backgroundColor = .black
view.delegate = self
view.frame = CGRect(x: 0, y: 0, width: collectionView.frame.width, height: 100) //delete this line
view.item = banners[indexPath.section % banners.count]
return view
}
I delete the line set frame for header view and it's works
In my app, I'm using dynamic height cells using auto layout. So for creating cardview effect I've to use tableview willdisplaycell method. It only add shadow only once to cell. But I don't know why shadow increasing while scrolling.
Here's my code
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
//setup card view style on cell
if !cellArray.contains(indexPath.row) {
cell.contentView.backgroundColor = UIColor.clear
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 5.0, y: 5.0, width: cell.contentView.frame.size.width-10, height: cell.contentView.frame.size.height-10))
whiteRoundedView.layer.backgroundColor = UIColor.white.cgColor
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.cornerRadius = 5.0
whiteRoundedView.layer.shadowOffset = CGSize(width: -1, height: 1)
whiteRoundedView.layer.shadowOpacity = 0.5
cell.contentView.addSubview(whiteRoundedView)
cell.contentView.sendSubview(toBack: whiteRoundedView)
cellArray.add(indexPath.row)
}
}
this piece of line is the causing the issue.
cell.contentView.addSubview(whiteRoundedView)
whenever willDisplayCell gets called, you will be adding the view everytime. That is the reason shadow is getting increased while scrolling. The solution is,
1. check the cell content view if the view is already added or not. If not, then add the view. use view tag to do it.
2. otherwise, create a shadow view and initialize the specific things in the -(void)awakeFromNib, which will get called only once.
but personally, i prefer option 2, which will isolate your view render logic from view controller or cell.
add the below code to your custom cell class. In this case, i have given leading-trialing-top-bottom constraints as 15-15-15-15. If you wish you can set it to 0. but make sure that it should in sync with the background constraints.
override func awakeFromNib() {
super.awakeFromNib()
contentView.backgroundColor = UIColor.clear
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 5.0, y: 5.0, width: contentView.frame.size.width-10, height: contentView.frame.size.height-10))
whiteRoundedView.layer.backgroundColor = UIColor.white.cgColor
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.cornerRadius = 5.0
whiteRoundedView.layer.shadowOffset = CGSize(width: -1, height: 1)
whiteRoundedView.layer.shadowOpacity = 0.5
whiteRoundedView.tag = shadowTag
whiteRoundedView.translatesAutoresizingMaskIntoConstraints=false
contentView.addSubview(whiteRoundedView)
contentView.sendSubview(toBack: whiteRoundedView)
let leading = NSLayoutConstraint(item: whiteRoundedView,
attribute: .leading,
relatedBy: .equal,
toItem: contentView,
attribute: .leading,
multiplier: 1.0,
constant: 15.0)
let trailing = NSLayoutConstraint(item: whiteRoundedView,
attribute: .trailing,
relatedBy: .equal,
toItem: contentView,
attribute: .trailing,
multiplier: 1.0,
constant: -15.0)
let top = NSLayoutConstraint(item: whiteRoundedView,
attribute: .top,
relatedBy: .equal,
toItem: contentView,
attribute: .top,
multiplier: 1.0,
constant: 15.0)
let bottom = NSLayoutConstraint(item: whiteRoundedView,
attribute: .bottom,
relatedBy: .equal,
toItem: contentView,
attribute: .bottom,
multiplier: 1.0,
constant: -15.0)
contentView.addConstraint(leading)
contentView.addConstraint(trailing)
contentView.addConstraint(top)
contentView.addConstraint(bottom)
}
Ref screenshot :
You can add your code here
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: <idenitfier>, for: indexPath) as? JobListTableViewCell
if cell == nil {
//Initialization and setting of shadow
}
return cell
}
Hope this helps
To make uiview on top of all tabs of uitabbar controller .
I planned to make one baseviewcontroller named "uiView.swift" .In "uiView.swift" i added my uiview. After that i want to inherit each tab ViewController (say "resturent.swift") from that uiView.swift. So, in each tab of UITabBarController you will get that "uiView.swift" view resued.uiView.swift is connected to ViewController in Storyboard that has button that show the view on button click .Here is my "uiView.swift"
class uiView: UIViewController {
var menuView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
menuView = UIView(frame: CGRect(x: 0, y: -200, width: 420, height: 200))
menuView?.backgroundColor = UIColor.green
view.addSubview(menuView!)
}
#objc func MyBag(){
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func collectionmenuone(_ sender: Any) {
menuView=UIView(frame: CGRect(x: 0, y: 0, width: 420, height: 200))
menuView?.backgroundColor=UIColor.lightGray
self.view.addSubview(menuView!)
var btnbag = UIButton(type: .roundedRect)
btnbag.addTarget(self, action: #selector(self.MyBag), for: .touchUpInside)
btnbag.frame = CGRect(x: 104, y:130 , width: 150, height: 60)
btnbag.setTitle("Done", for: .normal)
btnbag.backgroundColor=UIColor.green
menuView?.addSubview(btnbag)
}
}
how i can make possible reuse of view from "uiView.swift" in each tab of tabbar controller (i.e "resturent.swif")
class resturent:UICollectionViewController,UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title="Seafood"
collectionView?.backgroundColor=UIColor.white
// view.backgroundColor=UIColor.redColor
collectionView?.register(VideoCell.self, forCellWithReuseIdentifier: "cellid")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: "cellid", for: indexPath)
// cell.backgroundColor=UIColor.red
return cell
}
/* override func collectionView(collectionView: UICollectionView, cellForItemAtIndexpath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath as IndexPath)
return cell
}*/
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height=(view.frame.width - 16 - 16) * 9/16
return CGSize(width: view.frame.width, height: height + 16 + 68)
}
}
class VideoCell:UICollectionViewCell{
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
let thumbnailImageView:UIImageView = {
let imageView=UIImageView()
imageView.backgroundColor=UIColor.blue
imageView.image=UIImage(named: "food24")
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds=true
return imageView
}()
let userProfileImageView:UIImageView={
let imageView=UIImageView()
//imageView.backgroundColor=UIColor.green
return imageView
}()
let separatorView:UIView = {
let view = UIView ()
view.backgroundColor=UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1)
return view
}()
let titleLabel:UILabel={
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints=false
label.text="Resturant name here"
return label
}()
let subtitleTextView:UITextView = {
let textView=UITextView()
textView.translatesAutoresizingMaskIntoConstraints=false
textView.textContainerInset=UIEdgeInsetsMake(0, -4, 0, 0)
textView.textColor=UIColor.lightGray
textView.text = "SeaFood"
return textView
}()
func setupView() {
//backgroundColor=UIColor.blue
addSubview(thumbnailImageView)
addSubview(separatorView)
addSubview(userProfileImageView)
addSubview(titleLabel)
addSubview(subtitleTextView)
addConstraintsWithFormat(format: "H:|-16-[v0]-16-|", view: thumbnailImageView)
addConstraintsWithFormat(format: "H:|-16-[v0(44)]", view: userProfileImageView)
//vertial constratints
addConstraintsWithFormat(format: "V:|-16-[v0]-8-[v1(44)]-16-[v2(1)]|", view: thumbnailImageView,userProfileImageView,separatorView)
addConstraintsWithFormat(format: "H:|[v0]|", view: separatorView)
//top constraints
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem:thumbnailImageView , attribute: .bottom, multiplier: 1, constant: 8))
//left constaints
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 8, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
//top constraints
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .top, relatedBy: .equal, toItem:titleLabel , attribute: .bottom, multiplier: 1, constant: 4))
//left constaints
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 8, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
// addConstraintsWithFormat(format: "V:[v0(20)]", view: titleLabel)
// addConstraintsWithFormat(format: "H:|[v0]|", view: titleLabel)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension UIView{
func addConstraintsWithFormat(format:String,view:UIView...){
var viewDictionary=[String:UIView]()
for (index,view) in view.enumerated(){
let key="v\(index)"
view.translatesAutoresizingMaskIntoConstraints=false
viewDictionary[key]=view
}
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: format , options: NSLayoutFormatOptions(), metrics: nil, views: viewDictionary))
}
}
uiView.swift is of type UIViewController and resturent.swif is of type UICollectionViewController.You can change the entry point of app from uiView.swift to login View controller(Viewcontroller.swift) to run app.How by inheritance i can reuse the view in uiView.swift ?you can download the project from this link .https://drive.google.com/file/d/1XSwOZcfvglB_7Zt_E8W8W3Dym3i1_lrB/view?usp=sharing
You should not add your menu View on any of your view. Instead of this you can direct add it on your window from AppDelegate.
Adding a view on window will place it above all the views that is been currently visible.
I have custom keyboard with a UICollectionView. The cells do not have a defined size. When rotating the device from portrait to landscape the keyboard resizes appropriately but the UICollectionView stays at the original width.
What is the best way to tackle updating the width to expand to the full available with? How can I update the constraints to the available space?
The UICollectionView is created programmatically and I'm not using a storyboard to implement AutoLayout that way.
override func viewDidAppear(animated: Bool) {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.registerNib(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: kbReuseIdentifier)
collectionView.backgroundColor = UIColor.whiteColor()
self.collectionView.translatesAutoresizingMaskIntoConstraints = true
self.view.addSubview(collectionView)
let collectionViewBottomConstraint = NSLayoutConstraint(item: self.collectionView, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: -40.0)
let collectionViewTopConstraint = NSLayoutConstraint(item: self.collectionView, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1.0, constant: 10)
let collectionViewLeftConstraint = NSLayoutConstraint(item: self.collectionView, attribute: .LeadingMargin, relatedBy: .Equal, toItem: self.view, attribute: .LeadingMargin, multiplier: 1.0, constant: 0)
let collectionViewRightConstraint = NSLayoutConstraint(item: self.collectionView, attribute: .TrailingMargin, relatedBy: .Equal, toItem: self.view, attribute: .TrailingMargin, multiplier: 1.0, constant: 0)
self.view.addConstraints([collectionViewBottomConstraint, collectionViewTopConstraint, collectionViewRightConstraint, collectionViewLeftConstraint])
}
You need to implement the UICollectionViewDelegateFlowLayout protocol on your view controller.
On viewDidLoad, register for orientation changed notifications:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationDidChange:", name: UIDeviceOrientationDidChangeNotification, object: nil)
Don't forget to remove the observer when the viewController is closed:
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
When the orientation changes, tell the collectionView to update the layout:
func orientationDidChange(notification: NSNotification) {
collectionView!.collectionViewLayout.invalidateLayout()
}
Finally, implement the UICollectionViewDelegateFlowLayout protocol method. On this method you can calculate the size for your collection view cells as needed, by referencing the collectionView frame width or the device screen size:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
// Leave 10px margin on each side, plus 10px between columns
let columns = 2
let margings = 20 + 10 * (columns - 1)
let width = (collectionView.frame.size.width - margings) / columns
let height = width // square cells
return CGSizeMake(width, height)
}
In my case, I want the cells to always be proportional to the portrait screen ratio. Also I have a variable number of columns, but that might not be your case.
Try overriding updateViewConstraints, check what is the current orientation with UIInterfaceOrientationIsPortrait(UIApplication.sharedApplication().statusBarOrientation/UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation and update the constant of certain constraints in your NSAutoLayout logic.