diff --git a/programmatic-ui-weather-app/View Controllers/MainVC/HourlyCollectionViewCell/HourlyCollectionViewCell.swift b/programmatic-ui-weather-app/View Controllers/MainVC/HourlyCollectionViewCell/HourlyCollectionViewCell.swift new file mode 100644 index 0000000..9862f03 --- /dev/null +++ b/programmatic-ui-weather-app/View Controllers/MainVC/HourlyCollectionViewCell/HourlyCollectionViewCell.swift @@ -0,0 +1,39 @@ +// +// HourlyCollectionViewCell.swift +// weatherkit-weather-app +// +// Created by Ruslan Spirkin on 7/28/23. +// + +import UIKit + +class CustomCell: UICollectionViewCell { + // Add UI elements as needed + var titleLabel: UILabel! + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupUI() + } + + private func setupUI() { + titleLabel = UILabel() + titleLabel.textAlignment = .center + titleLabel.font = UIFont.systemFont(ofSize: 16.0) + contentView.addSubview(titleLabel) + + // Add constraints or adjust frames + titleLabel.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor), + titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) + ]) + } +} diff --git a/programmatic-ui-weather-app/View Controllers/MainVC/MainViewController.swift b/programmatic-ui-weather-app/View Controllers/MainVC/MainViewController.swift index 08bf5a5..6510a4f 100644 --- a/programmatic-ui-weather-app/View Controllers/MainVC/MainViewController.swift +++ b/programmatic-ui-weather-app/View Controllers/MainVC/MainViewController.swift @@ -16,7 +16,7 @@ struct UserLocation { static var userCLLocation: CLLocation? } -class MainViewController: UIViewController, CLLocationManagerDelegate, UIScrollViewDelegate { +class MainViewController: UIViewController, CLLocationManagerDelegate, UIScrollViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource { //cyanColor constant (used in precipitationView, hourlyForecastView, etc.) let cyanColor = UIColor(red: 95.0/255.0, green: 195.0/255.0, blue: 255.0/255.0, alpha: 0.93) @@ -72,6 +72,11 @@ class MainViewController: UIViewController, CLLocationManagerDelegate, UIScrollV let windTitleLabel = UILabel() let windLabel = UILabel() + // Data for your collection view cells + let cellData = ["Cell 1", "Cell 2", "Cell 3", "Cell 4", "Cell 5"] + let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout.init()) +// let layoutCollectionView:UICollectionViewFlowLayout = UICollectionViewFlowLayout.init() + //Creates a refresh control for the scrollview var refreshControl = UIRefreshControl() //Creates the location manager @@ -93,6 +98,7 @@ class MainViewController: UIViewController, CLLocationManagerDelegate, UIScrollV // For use in foreground self.locationManager.requestWhenInUseAuthorization() + configureCollectionView() //Initalizes settings for UI elements and layout for UI elements style() layout() @@ -315,6 +321,10 @@ class MainViewController: UIViewController, CLLocationManagerDelegate, UIScrollV bottomLabel5.text = "--" bottomLabel5.font = .preferredFont(forTextStyle: .body) + //CollectionView + collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.showsHorizontalScrollIndicator = false + let windTapGesture = UITapGestureRecognizer(target: self, action: #selector(windSpeedTapped)) windView.translatesAutoresizingMaskIntoConstraints = false windView.backgroundColor = cyanColor @@ -388,6 +398,7 @@ class MainViewController: UIViewController, CLLocationManagerDelegate, UIScrollV //Adds elements into hourlyForecastView hourlyForecastView.addSubview(hourlyForecastTitleLabel) hourlyForecastView.addSubview(scrollview) + hourlyForecastView.addSubview(collectionView) //Adds Views into main view @@ -450,6 +461,11 @@ class MainViewController: UIViewController, CLLocationManagerDelegate, UIScrollV horizontalStack.leadingAnchor.constraint(equalTo: scrollview.leadingAnchor), horizontalStack.trailingAnchor.constraint(equalTo: scrollview.trailingAnchor), horizontalStack.bottomAnchor.constraint(equalTo: scrollview.bottomAnchor), + //HourlyCollectionView constraints + collectionView.topAnchor.constraint(equalTo: horizontalStack.bottomAnchor), + collectionView.leadingAnchor.constraint(equalTo: scrollview.leadingAnchor), + collectionView.trailingAnchor.constraint(equalTo: scrollview.trailingAnchor), + collectionView.bottomAnchor.constraint(equalTo: scrollview.bottomAnchor), //windView constraints windView.topAnchor.constraint(equalTo: hourlyForecastView.bottomAnchor, constant: 20), windView.leadingAnchor.constraint(equalTo: hourlyForecastView.leadingAnchor), @@ -730,4 +746,31 @@ extension MainViewController { self.present(windSpeedPopUp, animated: true) } } + + //MARK: Hourly Forecast Collection View + private func configureCollectionView() { + collectionView.delegate = self + collectionView.dataSource = self + + // Register your custom cell class + collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell") + + // Set the collection view's layout to horizontal scroll + if let layout2 = collectionView.collectionViewLayout as? UICollectionViewFlowLayout { + layout2.scrollDirection = .horizontal + } + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return cellData.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell + + // Customize your cell here based on the data + cell.titleLabel.text = cellData[indexPath.item] + + return cell + } } diff --git a/weatherkit-weather-app.xcodeproj/project.pbxproj b/weatherkit-weather-app.xcodeproj/project.pbxproj index 6eb2972..05e4e2f 100644 --- a/weatherkit-weather-app.xcodeproj/project.pbxproj +++ b/weatherkit-weather-app.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ C0711C2729484644004D3BD3 /* JosefinSans-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C0711C2129484643004D3BD3 /* JosefinSans-Light.ttf */; }; C0711C2929484FD3004D3BD3 /* SunriseSunsetPopUpVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0711C2829484FD3004D3BD3 /* SunriseSunsetPopUpVC.swift */; }; C0711C2C2949667B004D3BD3 /* WindSpeedPopUpVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0711C2B2949667B004D3BD3 /* WindSpeedPopUpVC.swift */; }; + C072FF462A742F8900CCF9B1 /* HourlyCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C072FF452A742F8900CCF9B1 /* HourlyCollectionViewCell.swift */; }; C0A2111A2952E21C00C05917 /* AnimationsEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0A211192952E21C00C05917 /* AnimationsEffects.swift */; }; C0B01BCC291334AC00D887C6 /* WeatherKitCallUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B01BCB291334AC00D887C6 /* WeatherKitCallUtil.swift */; }; C0B01BF3291F361900D887C6 /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B01BF2291F361800D887C6 /* TabBarViewController.swift */; }; @@ -133,6 +134,7 @@ C0711C2129484643004D3BD3 /* JosefinSans-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "JosefinSans-Light.ttf"; sourceTree = ""; }; C0711C2829484FD3004D3BD3 /* SunriseSunsetPopUpVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SunriseSunsetPopUpVC.swift; sourceTree = ""; }; C0711C2B2949667B004D3BD3 /* WindSpeedPopUpVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindSpeedPopUpVC.swift; sourceTree = ""; }; + C072FF452A742F8900CCF9B1 /* HourlyCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HourlyCollectionViewCell.swift; sourceTree = ""; }; C086977929A5BE8800B458CA /* WatchWeather Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WatchWeather Model.swift"; sourceTree = ""; }; C0A211192952E21C00C05917 /* AnimationsEffects.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimationsEffects.swift; sourceTree = ""; }; C0B01BCA2912B08A00D887C6 /* programmatic-ui-weather-app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "programmatic-ui-weather-app.entitlements"; sourceTree = ""; }; @@ -339,6 +341,14 @@ path = "Forecast Model"; sourceTree = ""; }; + C072FF442A742F6700CCF9B1 /* HourlyCollectionViewCell */ = { + isa = PBXGroup; + children = ( + C072FF452A742F8900CCF9B1 /* HourlyCollectionViewCell.swift */, + ); + path = HourlyCollectionViewCell; + sourceTree = ""; + }; C086977B29A5BE9A00B458CA /* Model */ = { isa = PBXGroup; children = ( @@ -359,6 +369,7 @@ C0A68C73293BF22E000A24DC /* MainVC */ = { isa = PBXGroup; children = ( + C072FF442A742F6700CCF9B1 /* HourlyCollectionViewCell */, C034704228F6221900656AA8 /* MainViewController.swift */, ); path = MainVC; @@ -598,6 +609,7 @@ C0711C2929484FD3004D3BD3 /* SunriseSunsetPopUpVC.swift in Sources */, C0D265C0297635480079FBE3 /* WeatherKitData.swift in Sources */, C04E9E9F29417FA100882FC6 /* WidgetStruct.swift in Sources */, + C072FF462A742F8900CCF9B1 /* HourlyCollectionViewCell.swift in Sources */, C0CF2DD22929487800359476 /* SettingsListVC.swift in Sources */, C034704328F6221900656AA8 /* MainViewController.swift in Sources */, C05606FE2A61CEBA00F3C705 /* SwiftUIBackgroundBlur.swift in Sources */, @@ -800,7 +812,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.6.4; + MARKETING_VERSION = 0.6.5; PRODUCT_BUNDLE_IDENTIFIER = "com.ES.weatherkit-programmatic-app"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -839,7 +851,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.6.4; + MARKETING_VERSION = 0.6.5; PRODUCT_BUNDLE_IDENTIFIER = "com.ES.weatherkit-programmatic-app"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -869,7 +881,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.6.4; + MARKETING_VERSION = 0.6.5; PRODUCT_BUNDLE_IDENTIFIER = "com.ES.weatherkit-programmatic-app.weatherkit-widget"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -897,7 +909,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.6.4; + MARKETING_VERSION = 0.6.5; PRODUCT_BUNDLE_IDENTIFIER = "com.ES.weatherkit-programmatic-app.weatherkit-widget"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/weatherkit-weather-app.xcodeproj/project.xcworkspace/xcuserdata/RuslanS.xcuserdatad/UserInterfaceState.xcuserstate b/weatherkit-weather-app.xcodeproj/project.xcworkspace/xcuserdata/RuslanS.xcuserdatad/UserInterfaceState.xcuserstate index 67a386d..7882804 100644 Binary files a/weatherkit-weather-app.xcodeproj/project.xcworkspace/xcuserdata/RuslanS.xcuserdatad/UserInterfaceState.xcuserstate and b/weatherkit-weather-app.xcodeproj/project.xcworkspace/xcuserdata/RuslanS.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/weatherkit-weather-app.xcodeproj/xcuserdata/RuslanS.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/weatherkit-weather-app.xcodeproj/xcuserdata/RuslanS.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 0abf39d..2b3cfdf 100644 --- a/weatherkit-weather-app.xcodeproj/xcuserdata/RuslanS.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/weatherkit-weather-app.xcodeproj/xcuserdata/RuslanS.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -192,8 +192,8 @@ filePath = "programmatic-ui-weather-app/View Controllers/MainVC/MainViewController.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "323" - endingLineNumber = "323" + startingLineNumber = "333" + endingLineNumber = "333" landmarkName = "style()" landmarkType = "7"> @@ -208,8 +208,8 @@ filePath = "programmatic-ui-weather-app/View Controllers/MainVC/MainViewController.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "320" - endingLineNumber = "320" + startingLineNumber = "330" + endingLineNumber = "330" landmarkName = "style()" landmarkType = "7">