ALAMOFIRE post request image download and binding in a UICollectionView - swift

I need to download images I created a alamofire post request with parameter i dont have any problem in that . After that i need to download the image url from the Json response generated, I dont know how to download the image url from json and keep that in a array , after that have to download the inage from the url need to bind it in a image view of collectionView . I dont have any idea about how to take the image url from the json response then keep that in a array , then have to download the image bind it in a collectionView. Please help me
I have updated the json response for my post request. please give me a solution. I can get the below response in console.
( {
ActualPrice = 0;
AssuredTitle = "<null>";
CashBackAmount = 0;
CashBackDiscountPercentage = 0;
Code = "";
Cost = "<null>";
CreateDate = "<null>";
CustomSize = 0;
Delivery = "<null>";
DeliveryDate = "<null>";
DeliveryDays = "<null>";
Designer = "<null>";
Discount = "<null>";
DiscountCost = "<null>";
DispatchDateDisplay = "<null>";
Exclusive = "<null>";
Gender = "<null>";
HasReadyMadeColor = 0;
HasReadyMadeSizes = 0;
ID = 41;
ImageUrl = "https://images.cbazaar.com/images/aqua-blue-georgette-abaya-isbs1805991-u.jpg";
Is7DD = "<null>";
IsCustomizable = 0;
IsExclusive = 0;
IsFree = "<null>";
IsFreeShipping = 0;
IsInWishlist = 0;
IsLookUp = 0;
IsNew = 0;
IsProductAnimation = 0;
IsReadyToShip = 0;
LargeImageUrl = "<null>";
ListingImage = "<null>";
LowerLargeImage = "<null>";
LowerThumbImage = "<null>";
MoneyFactor = "<null>";
MoneyOffFactor = "<null>";
Name = "Islamic wear";
OfferImageUrl = "<null>";
OldPrice = 0;
OutOfStock = 0;
PDUrl = "<null>";
ProductBigLink = "<null>";
ProductCollectionReference = "<null>";
ProductHisImage = "<null>";
ProductSaleCycle = 0;
ProductType = 168;
ProductV2VRatio = 0;
PromotionTypeID = "<null>";
Promotions = "<null>";
PromotionsIcon = "<null>";
Rating = "<null>";
SalePrice = "<null>";
ShowOldPrice = 0;
SizeChart = "<null>";
SuperClassification = "<null>";
TypeGroup = "<null>";
TypeShortCode = "<null>";
UpperLargeImage = "<null>";
UpperThumbImage = "<null>";
VendorType = "<null>";
VisitCount = 0;
})
Complete ViewController File
import UIKit
import Alamofire
import AlamofireImage
class EthnoVogueDesignConsultationViewController: UIViewController, UIScrollViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var header_scrollView: UIScrollView!
#IBOutlet weak var pagecontroller: UIPageControl!
#IBOutlet weak var step_label: UILabel!
#IBOutlet weak var segmented_View: UIView!
#IBOutlet weak var segmented_Control: UISegmentedControl!
#IBOutlet weak var stylistView: UIView!
#IBOutlet weak var categorycollectionview: UICollectionView!
#IBOutlet weak var pagecontrollerview: UIView!
let image_array = ["slider1","slider2","slider1","slider2"]
let name_label = ["Salwar kameez","saree", "Anarkali", "Leghenga"]
static var deepLinkingFlag:Int = 0
static var deepLinkingFlagAfterKilling:Int = 0
var httpObj = HTTPHelper()
var apiRequestParameters:NSMutableDictionary = NSMutableDictionary()
var dictResult: NSDictionary = NSDictionary()
// var imageCache = [String:UIImage]()
//Array of images from the URL
var imageArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
globalConstants.deepLinkingFlagAfterKilling = 0
globalConstants.deepLinkingFlag = 0
apiclass()
// imagedownload()
//View which holds the stylist Name
stylistView.backgroundColor = UIColor(red: 235/255, green: 232/255, blue: 232/255, alpha: 1)
pagecontrollerview.backgroundColor = UIColor(red: 235/255, green: 232/255, blue: 232/255, alpha: 1)
//Label with holds the step 1
step_label.layer.borderWidth = 2
step_label.layer.borderColor = UIColor(red: 249/255, green: 8/255, blue: 129/255, alpha: 1).cgColor
stylistView.layer.shadowOffset = CGSize(width: 1, height: 1)
step_label.layer.shadowOpacity = 4
step_label.layer.shadowColor = UIColor(red: 249/255, green: 8/255, blue: 129/255, alpha: 1).cgColor
//Customising the segmented control with background color and tint color, font size
segmented_Control.tintColor = UIColor(red: 249/255, green: 8/255, blue: 129/255, alpha: 1)
segmented_Control.backgroundColor = UIColor.white
segmented_Control.layer.cornerRadius = 20
// let font = UIFont.systemFont(ofSize: 20)
let font = UIFont.boldSystemFont(ofSize: 20)
segmented_Control.setTitleTextAttributes([NSAttributedStringKey.font: font],
for: .normal)
let cellSize = CGSize(width:250 , height:400)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = cellSize
layout.sectionInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
layout.minimumLineSpacing = 10.0
layout.minimumInteritemSpacing = 10.0
categorycollectionview.setCollectionViewLayout(layout, animated: true)
categorycollectionview.setCollectionViewLayout(layout, animated: false)
categorycollectionview.delegate = self
categorycollectionview.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
self.header_scrollView.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:225)
let scrollViewWidth:CGFloat = self.header_scrollView.frame.width
let scrollViewHeight:CGFloat = self.header_scrollView.frame.height
header_scrollView.backgroundColor = UIColor.black
//set image to the particular image in uiscrollview
let imgOne = UIImageView(frame: CGRect(x:0, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgOne.image = UIImage(named: "slider2")
let imgTwo = UIImageView(frame: CGRect(x:scrollViewWidth, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgTwo.image = UIImage(named: "slider1")
//Adding subview for the scrollview
self.header_scrollView.addSubview(imgOne)
self.header_scrollView.addSubview(imgTwo)
//setting size of the content view
self.header_scrollView.contentSize = CGSize(width:self.header_scrollView.frame.width * 4, height:self.header_scrollView.frame.height)
//header scroll view delegate selection
self.header_scrollView.delegate = self
self.pagecontroller.currentPage = 0
// time interval to move the slide show
Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(moveToNextPage), userInfo: nil, repeats: true)
//step label for rounded corners
step_label.layer.masksToBounds = true
step_label.layer.cornerRadius = 15.0
NotificationCenter.default.addObserver(self, selector: #selector(EthnoVogueDesignConsultationViewController.deepLinking(_:)), name:NSNotification.Name(rawValue: "deepLinking"), object: nil)
}
#objc func deepLinking(_ notification:Notification){
print("its here")
// globalConstants.isSortCleared = 0
if(globalConstants.deepLinkingFlag == 1){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"catalog") as? CatalogController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 2){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"productDetails") as? ProductDetailViewController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 3){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"ols") as? OLSViewController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 4){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"home") as? HomeController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 5){
//self.navigationController?.popToRootViewControllerAnimated(false)
self.tabBarController?.selectedIndex = 1
}
else if(globalConstants.deepLinkingFlag == 6){
//self.navigationController?.popToRootViewControllerAnimated(false)
self.tabBarController?.selectedIndex = 2
}
else if(globalConstants.deepLinkingFlag == 7){
//self.navigationController?.popToRootViewControllerAnimated(false)
self.tabBarController?.selectedIndex = 0
}
}
// move to next image image view in file
#objc func moveToNextPage (){
let pageWidth:CGFloat = self.header_scrollView.frame.width
let maxWidth:CGFloat = pageWidth * 2
let contentOffset:CGFloat = self.header_scrollView.contentOffset.x
var slideToX = contentOffset + pageWidth
if contentOffset + pageWidth == maxWidth
{
slideToX = 0
}
self.header_scrollView.scrollRectToVisible(CGRect(x:slideToX, y:0, width:pageWidth, height:self.header_scrollView.frame.height), animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//scrollView Method for chaning the page control while swiping the image
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pagenumber = scrollView.contentOffset.x / scrollView.frame.size.width
pagecontroller.currentPage = Int(pagenumber)
}
//CollectionView for Categories image
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch segmented_Control.selectedSegmentIndex {
case 0:
return imageArray.count
case 1:
return 10
default:
break
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imagecell", for: indexPath) as! CategorySegmentCollectionViewCell
let url = NSURL(string: self.imageArray[indexPath.item])!
Cell.category_image.af_setImage(withURL: url as URL, placeholderImage: UIImage(named: "noimage.png"), filter: nil, imageTransition: .noTransition, runImageTransitionIfCached: true, completion: nil)
switch segmented_Control.selectedSegmentIndex{
case 0:
// let img : UIImage = UIImage(named:"pink")!
//
// Cell.category_image.image = img
// Cell.category_name_label.text = name_label[indexPath.item]
break
case 1:
// let img : UIImage = UIImage(named:"dark")!
// Cell.category_image.image = img
// Cell.category_name_label.text = "condition"
break
default:
break
}
//let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "brandCell", for: indexPath) as! BrandCollectionViewCell
// use this to download images
return Cell
}
func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell {
cell.category_image.transform = .init(scaleX: 0.95, y: 0.95)
cell.contentView.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1)
}
}
}
func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell {
cell.category_image.transform = .identity
cell.contentView.backgroundColor = .clear
}
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
switch segmented_Control.selectedSegmentIndex{
case 0:
if (collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell) != nil {
self.segmented_Control.setEnabled(true, forSegmentAt: 1)
segmented_Control.selectedSegmentIndex = 1
collectionView.reloadData()
//print(cell)
}
break
case 1:
if (collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell) != nil {
self.segmented_Control.setEnabled(true, forSegmentAt: 2)
let categoryTaskVC = storyboard?.instantiateViewController(withIdentifier: "fabrics") as! FabricsViewController
self.navigationController?.pushViewController(categoryTaskVC, animated: true)
}
break
default:
break
}
}
override func viewWillAppear(_ animated: Bool) {
if(segmented_Control.selectedSegmentIndex == 0){
self.segmented_Control.setEnabled(false, forSegmentAt: 1)
self.segmented_Control.setEnabled(false, forSegmentAt: 2)
}
}
#IBAction func segmented_tapped_action(_ sender: Any) {
categorycollectionview.reloadData()
}
func apiclass(){
if(globalConstants.prefs.value(forKey: "authToken") == nil){
self.httpObj.getAuthToken()
}
else if(globalConstants.prefs.value(forKey: "authExpireDate") != nil && Date().compare((globalConstants.prefs.value(forKey: "authExpireDate") as? Date)!) == ComparisonResult.orderedDescending){
globalConstants.prefs.setValue(nil, forKey: "authToken")
self.httpObj.getAuthToken()
}
DispatchQueue.main.async(execute: {
if(globalConstants.prefs.value(forKey: "authToken") != nil){
var request:NSMutableURLRequest = NSMutableURLRequest(url: globalConstants.tokenUrl as URL)
let authToken:String = (globalConstants.prefs.value(forKey: "authToken") as? String)!
request = NSMutableURLRequest(url: globalConstants.tokenUrl as URL)
request.addValue("Bearer \(authToken)", forHTTPHeaderField: "Authorization")
request.addValue(UIDevice.current.identifierForVendor!.uuidString, forHTTPHeaderField: "X-Device-ID")
request.addValue((globalConstants.prefs.value(forKey: "UUID") as? String)!, forHTTPHeaderField: "X-Unique-ID")
request.addValue((globalConstants.prefs.value(forKey: "countryCode") as? String)!, forHTTPHeaderField: "X-Country-Code")
request.addValue((globalConstants.prefs.value(forKey: "currencyCode") as? String)!, forHTTPHeaderField: "X-Currency-Code")
request.addValue((globalConstants.prefs.value(forKey: "currencySymbol") as? String)!, forHTTPHeaderField: "X-Currency-Symbol")
request.addValue(String(stringInterpolationSegment: (globalConstants.prefs.value(forKey: "currencyFactor"))!), forHTTPHeaderField: "X-Currency-Factor")
request.addValue((globalConstants.prefs.value(forKey: "appSource") as? String)!, forHTTPHeaderField: "X-App-Source")
request.addValue(globalConstants.appVersion, forHTTPHeaderField: "X-App-Version")
request.addValue(String(stringInterpolationSegment: (globalConstants.prefs.value(forKey: "estoreId") as? Int)!), forHTTPHeaderField: "X-EStore-ID")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
if(globalConstants.prefs.value(forKey: "userEmail") != nil){
request.addValue((globalConstants.prefs.value(forKey: "userEmail") as? String)!, forHTTPHeaderField: "X-Email")
}
if(globalConstants.prefs.value(forKey: "userId") != nil){
request.addValue(String(stringInterpolationSegment: (globalConstants.prefs.value(forKey: "userId"))!), forHTTPHeaderField: "X-User-ID")
}
print(self.apiRequestParameters)
var requestParameters:NSMutableDictionary = NSMutableDictionary()
requestParameters = [
"mode" : "design",
"productGroup" : 0
]
print(requestParameters)
request.url = globalConstants.ESDCUrl as URL
self.httpObj.sendRequest("POST", requestDict: requestParameters, request: request as URLRequest, completion: { (result, error) in
print(result!)
if(error == nil){
guard let json = result as! [[String:Any]]? else{
return
}
print("Response \(json)")
for images in json
{
if let ImageUrl = images["ImageUrl"] as? String
{
self.imageArray.append(ImageUrl)
}
DispatchQueue.main.async {
self.categorycollectionview.reloadData()
}
}
// self.dictResult = result as! NSDictionary
// self.categorycollectionview.reloadData()
//self.collectionView.reloadData()
// let requestDataDict:NSDictionary = incomingRequetArray[0] as! NSDictionary
// let newDict: NSURL = requestDataDict.object(forKey: "ImageUrl") as? NSDictionary
//
}
else{
let alert = UIAlertView()
alert.isHidden = true
alert.addButton(withTitle: "OK")
alert.message = globalConstants.apiErrorMessage
alert.show()
}
})
}
})
}
//typealaising the headerscrollview to the view controller
private typealias Header_scrollView = EthnoVogueDesignConsultationViewController
// extending the header_scrollview
extension Header_scrollView
{
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView){
// Test the offset and calculate the current page after scrolling ends
let pageWidth:CGFloat = scrollView.frame.width
let currentPage:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
// Change the indicator
self.pagecontroller.currentPage = Int(currentPage);
UIView.animate(withDuration: 1.0, animations: { () -> Void in
// self.startButton.alpha = 1.0
})
}
}

Related

Custom Collection View layout: 'Invalid parameter not satisfying: self.supplementaryViewProvider'

I am using two collectionViews in my view controller. 1 has a custom layout and custom attributes for its supplementary views.
Here is the view controller:
class ProgressViewController: UIViewController {
private lazy var data = fetchData()
private lazy var recordsDataSource = makeRecordsDataSource()
private lazy var timelineDataSource = makeTimelineDataSource()
fileprivate typealias RecordsDataSource = UICollectionViewDiffableDataSource<YearMonthDay, TestRecord>
fileprivate typealias RecordsDataSourceSnapshot = NSDiffableDataSourceSnapshot<YearMonthDay, TestRecord>
fileprivate typealias TimelineDataSource = UICollectionViewDiffableDataSource<TimelineSection,YearMonthDay>
fileprivate typealias TimelineDataSourceSnapshot = NSDiffableDataSourceSnapshot<TimelineSection,YearMonthDay>
private var timelineMap = TimelineMap()
private var curItemIndex = 0
private var curRecordsOffset: CGFloat = 0
private var curTimelineOffset: CGFloat = 0
private var timelineStart: Date?
#IBOutlet var recordsCollectionView: UICollectionView!
#IBOutlet var timelineCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
data = fetchData()
timelineStart = Array(data.keys).first?.date
configureRecordsDataSource()
configureTimelineDataSource()
configureTimelineSupplementaryViews()
applyRecordsSnapshot()
applyTimelineSnapshot()
if let collectionViewLayout = timelineCollectionView.collectionViewLayout as? TimelineLayout {
collectionViewLayout.delegate = self
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
var i: CGFloat = 0
for _ in data {
let recordOffset = self.recordsCollectionView.frame.width * i
let timelineOffset = (timelineCollectionView.frame.width + CGFloat(10)) * i
timelineMap.set(recordOffset: recordOffset, timelineOffset: timelineOffset)
i += 1
}
}
private func fetchData() -> [YearMonthDay:[TestRecord]] {
var data: [YearMonthDay:[
TestRecord]] = [:]
var testRecords:[TestRecord] = []
for i in 0...6{
let testRecord = TestRecord(daysBack: i*2, progression: 0)
testRecords.append(testRecord)
}
for record in testRecords {
let ymd = YearMonthDay(date:record.timeStamp,records: [])
if var day = data[ymd] {
day.append(record)
} else {
data[ymd] = [record]
}
}
return data
}
extension ProgressViewController {
//RECORDS data
fileprivate func makeRecordsDataSource() -> RecordsDataSource {
let dataSource = RecordsDataSource(
collectionView: recordsCollectionView,
cellProvider: { (collectionView, indexPath, testRecord) ->
UICollectionViewCell? in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RecordCollectionViewCell.identifier, for: indexPath) as? RecordCollectionViewCell
cell?.configure(with: testRecord)
return cell
})
return dataSource
}
func configureRecordsDataSource() {
self.recordsCollectionView.register(RecordCollectionViewCell.nib, forCellWithReuseIdentifier: RecordCollectionViewCell.identifier)
}
func applyRecordsSnapshot() {
// 2
var snapshot = RecordsDataSourceSnapshot()
for (ymd,records) in data {
snapshot.appendSections([ymd])
snapshot.appendItems(records,toSection: ymd)
}
recordsDataSource.apply(snapshot, animatingDifferences: false)
}
}
extension ProgressViewController {
enum TimelineSection {
case main
}
fileprivate func makeTimelineDataSource() -> TimelineDataSource {
let dataSource = TimelineDataSource(
collectionView: self.timelineCollectionView,
cellProvider: { (collectionView, indexPath, testRecord) ->
UICollectionViewCell? in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimelineDayCell.identifier, for: indexPath) as? TimelineDayCell
cell?.backgroundColor = .orange
cell?.dayLabel.text = String(indexPath.section)+","+String(indexPath.row)
return cell
})
return dataSource
}
func configureTimelineDataSource() {
self.timelineCollectionView!.register(TimelineDayCell.nib, forCellWithReuseIdentifier: TimelineDayCell.identifier)
timelineCollectionView.register(
UINib(nibName: "MonthHeader", bundle: nil),
forSupplementaryViewOfKind: TimelineLayout.Element.month.kind,
withReuseIdentifier: TimelineLayout.Element.month.id)
timelineCollectionView.register(
UINib(nibName: "TimelineDayCell", bundle: nil),
forSupplementaryViewOfKind: TimelineLayout.Element.day.kind,
withReuseIdentifier: TimelineLayout.Element.day.id)
timelineCollectionView.register(
UINib(nibName: "YearLabel", bundle: nil),
forSupplementaryViewOfKind: TimelineLayout.Element.year.kind,
withReuseIdentifier: TimelineLayout.Element.year.id)
}
func applyTimelineSnapshot(animatingDifferences: Bool = false) {
// 2
var snapshot = TimelineDataSourceSnapshot()
snapshot.appendSections([.main])
snapshot.appendItems(Array(data.keys))
timelineDataSource.apply(snapshot, animatingDifferences: animatingDifferences)
}
func configureTimelineSupplementaryViews(){
timelineDataSource.supplementaryViewProvider = { (
collectionView: UICollectionView,
kind: String,
indexPath: IndexPath) -> UICollectionReusableView? in
switch kind {
case TimelineLayout.Element.month.kind:
let supplementaryView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: TimelineLayout.Element.month.id, for: indexPath)
if let monthLabelView = supplementaryView as? MonthHeader {
let active = Calendar.current.date(byAdding: .month, value: indexPath.item, to: self.timelineStart!)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM"
let monthString = dateFormatter.string(from: active!)
monthLabelView.monthLabel.text = monthString
}
return supplementaryView
case TimelineLayout.Element.year.kind:
let supplementaryView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: TimelineLayout.Element.year.id, for: indexPath)
if let yearLabelView = supplementaryView as? YearLabel {
let labelDate = Calendar.current.date(byAdding: .year, value: indexPath.item, to: self.timelineStart!)!
let year = Calendar.current.component(.year, from: labelDate)
yearLabelView.yearLabel.text = String(year)
}
return supplementaryView
default:
fatalError("This should never happen!!")
}
}
}
}
extension ProgressViewController: TimelineLayoutDelegate {
func collectionView(_ collectionView: UICollectionView, dateAtIndexPath indexPath: IndexPath) -> Date? {
return timelineDataSource.itemIdentifier(for: indexPath)?.date
}
}
Then in my custom TimelineLayout I have
class TimelineLayout: UICollectionViewLayout {
weak var delegate: TimelineLayoutDelegate!
enum Element: String {
case day
case month
case year
var id: String {
return self.rawValue
}
var kind: String {
return "Kind\(self.rawValue.capitalized)"
}
}
private var oldBounds = CGRect.zero
private var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
private var contentWidth = CGFloat()
private var cache = [Element: [IndexPath: UICollectionViewLayoutAttributes]]()
private var monthHeight: CGFloat = 19
private var yearHeight: CGFloat = 11
private var dayHeight: CGFloat = 30
private var cellWidth: CGFloat = 2.5
private var collectionViewStartY: CGFloat {
guard let collectionView = collectionView else {
return 0
}
return collectionView.bounds.minY
}
private var collectionViewHeight: CGFloat {
return collectionView!.frame.height
}
override public var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: collectionViewHeight)
}
}
extension TimelineLayout {
override public func prepare() {
guard let collectionView = collectionView,
cache.isEmpty else {
return
}
collectionView.decelerationRate = .fast
updateInsets()
cache.removeAll(keepingCapacity: true)
cache[.year] = [IndexPath: UICollectionViewLayoutAttributes]()
cache[.month] = [IndexPath: UICollectionViewLayoutAttributes]()
cache[.day] = [IndexPath: UICollectionViewLayoutAttributes]()
oldBounds = collectionView.bounds
var timelineStart: Date?
var timelineEnd: Date?
for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
let cellIndexPath = IndexPath(item: item, section: 0)
guard let cellDate = delegate.collectionView(collectionView, dateAtIndexPath: cellIndexPath) else {
return
}
if item == 0 {
let firstDate = cellDate
timelineStart = Calendar.current.startOfDay(for: firstDate)
}
if item == collectionView.numberOfItems(inSection: 0) - 1 {
timelineEnd = cellDate
}
let startX = CGFloat(cellDate.days(from: timelineStart!)) * cellWidth
let dayCellattributes = UICollectionViewLayoutAttributes(forCellWith: cellIndexPath)
dayCellattributes.frame = CGRect(x: startX, y: collectionViewStartY + yearHeight + monthHeight, width: cellWidth, height: dayHeight)
cache[.day]?[cellIndexPath] = dayCellattributes
contentWidth = max(startX + cellWidth,contentWidth)
}
///TODO - what if there are no items in the section....
guard let monthStart = timelineStart?.startOfMonth(), let monthEnd = timelineEnd?.endOfMonth() else { return }
let begin = Calendar.current.date(byAdding: .month, value: -4, to: monthStart)
let end = Calendar.current.date(byAdding: .month, value: 4, to: monthEnd)
var date: Date = begin!
let initalOffset = CGFloat((timelineStart?.days(from: date))!) * cellWidth
var monthOffset: CGFloat = 0
var monthIndex: Int = 0
var yearIndex: Int = 0
while date <= end! {
let daysInMonth = Calendar.current.range(of: .day, in: .month, for: date)?.count
let monthWidth = cellWidth * CGFloat(daysInMonth!)
//let monthIndex = date.months(from: timelineStart!)
let monthLabelIndexPath = IndexPath(item: monthIndex, section: 0)
let monthLabelAttributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: Element.month.kind, with: monthLabelIndexPath)
let startX = monthOffset - initalOffset
monthLabelAttributes.frame = CGRect(x: startX, y: collectionViewStartY + yearHeight, width: monthWidth, height: monthHeight)
print(startX,"spaghet")
cache[.month]?[monthLabelIndexPath] = monthLabelAttributes
monthOffset += monthWidth
if Calendar.current.component(.month, from: date) == 1 || yearIndex == 0 {
//draw year
//let year = Calendar.current.component(.year, from: date)
//let yearIndex = date.years(from: timelineStart!)
let daysFromStartOfYear = date.days(from: date.startOfYear())
let startYearX = startX - CGFloat(daysFromStartOfYear) * cellWidth
let yearLabelIndexPath = IndexPath(item: yearIndex, section: 0)
let yearLabelAttributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: Element.year.kind, with: yearLabelIndexPath)
yearLabelAttributes.frame = CGRect(x: startYearX, y: collectionViewStartY, width: CGFloat(30), height: yearHeight)
cache[.year]?[yearLabelIndexPath] = yearLabelAttributes
yearIndex += 1
}
date = Calendar.current.date(byAdding: .month, value: 1, to: date)!
monthIndex += 1
}
}
}
extension TimelineLayout {
public override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
switch elementKind {
case Element.year.kind:
return cache[.year]?[indexPath]
default:
return cache[.month]?[indexPath]
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
visibleLayoutAttributes.removeAll(keepingCapacity: true)
if let yearAttrs = cache[.year], let monthAttrs = cache[.month], let dayAttrs = cache[.day] {
for (_, attributes) in yearAttrs {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
for (_, attributes) in monthAttrs {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
for (_, attributes) in dayAttrs {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
// visibleLayoutAttributes.append(self.shiftedAttributes(from: attributes))
}
}
return visibleLayoutAttributes
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let attributes = cache[.day]?[indexPath] else { fatalError("No attributes cached") }
return attributes
// return shiftedAttributes(from: attributes)
}
override public func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
if oldBounds.size != newBounds.size {
cache.removeAll(keepingCapacity: true)
}
return true
}
override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext) {
if context.invalidateDataSourceCounts { cache.removeAll(keepingCapacity: true) }
super.invalidateLayout(with: context)
}
}
As you can see I do create timelineDataSource supplementary View Provider in the view controller. Then in the Timeline Layout I implement layoutAttributesForElements(in rect: CGRect) and layoutAttributesForSupplementaryView(ofKind .... The latter never gets called - the error comes first. layoutAttributesForElements(in rect: CGRect) does get called and filled with dayAttrs, monthAttrs, and yearAttrs. However still, the error occurs afterwards:
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: self.supplementaryViewProvider || (self.supplementaryReuseIdentifierProvider && self.supplementaryViewConfigurationHandler)'
terminating with uncaught exception of type NSException
What am I missing?
Edit: I want to add the detail that when I put a breakpoint in that supplementaryViewProvider it's never called. So maybe I am doing something wrong in layoutAttributesForElements(in Rect?)

UICollectionView is running before the data load from Web Api

UICollectionView is running before data(finalAllItems) is populated from web api. I should show UICollectionView with data. I have added below line end of the convertReturnsInToWantedType function. But it did not fix the problem. outletForTheCollectionView.reloadData() How can I show data in UICollectionView?
import UIKit
class HomeViewController: UIViewController {
#IBOutlet weak var outletForTheCollectionView: UICollectionView!
#IBOutlet weak var outletForThePageController: UIPageControl!
var howmanyWords : Int = 0
var dataList : [[String:Any]]?
var finalAllItems = [AllItems]()
override func viewDidLoad() {
super.viewDidLoad()
loadVerbs()
outletForTheCollectionView.delegate = self
outletForTheCollectionView.dataSource = self
let xib = UINib(nibName: "CustomCell", bundle: nil)
self.outletForTheCollectionView.register(xib, forCellWithReuseIdentifier: "ViewCellID")
}
func loadVerbs ()
{
let urlString = "http://somelink/english/vocabularyVerbs.ashx"
let url = URL(string: urlString)
let request = URLRequest(url: url!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 30.0)
let task = URLSession.shared.dataTask(with: request)
{
(data, response, error) in
if let result = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [[String:Any]]
{
DispatchQueue.main.async
{
self.dataList = result
self.convertReturnsInToWantedType()
}
}
}
task.resume()
}
func convertReturnsInToWantedType()
{
// I populate finalAllItems array of dictionary object in here.
// Code might be not well-written in this scope
var datalistCount = dataList!.count
howmanyWords = datalistCount
datalistCount = datalistCount - 1
let nullLabel : String = "variable is coming null from web api"
for n in 0...datalistCount {
let oneItem = self.dataList![n]
var itemWord : String = ""
if let itemWordTemp = oneItem["itemWord"] as? String
{
itemWord = itemWordTemp
}
else
{
itemWord = nullLabel
}
var itemMeaning : String = ""
if let itemMeaningTemp = oneItem["itemMeaning"] as? String
{
itemMeaning = itemMeaningTemp
}
else
{
itemMeaning = nullLabel
}
var itemVerb2Form : String = ""
if let itemVerb2FormTemp = oneItem["itemVerb2Form"] as? String
{
itemVerb2Form = itemVerb2FormTemp
}
else
{
itemVerb2Form = nullLabel
}
var itemVerb3Form : String = ""
if let itemVerb3FormTemp = oneItem["itemVerb3Form"] as? String
{
itemVerb3Form = itemVerb3FormTemp
}
else
{
itemVerb3Form = nullLabel
}
var itemDefination : String = ""
if let itemDefinationTemp = oneItem["itemDefination"] as? String
{
itemDefination = itemDefinationTemp
}
else
{
itemDefination = nullLabel
}
var itemUsingInSentence : String = ""
if let itemUsingInSentenceTemp = oneItem["itemUsingInSentence"] as? String
{
itemUsingInSentence = itemUsingInSentenceTemp
}
else
{
itemUsingInSentence = nullLabel
}
var itemThisWordIsRelatedWithThatWord : String = ""
if let itemThisWordIsRelatedWithThatWordTemp = oneItem["itemThisWordIsRelatedWithThatWord"] as? String
{
itemThisWordIsRelatedWithThatWord = itemThisWordIsRelatedWithThatWordTemp
}
else
{
itemThisWordIsRelatedWithThatWord = nullLabel
}
var itemTrapReply1 : String = ""
if let itemTrapReply1Temp = oneItem["itemTrapReply1"] as? String
{
itemTrapReply1 = itemTrapReply1Temp
}
else
{
itemTrapReply1 = nullLabel
}
var itemTrapReply2 : String = ""
if let itemTrapReply2Temp = oneItem["itemTrapReply2"] as? String
{
itemTrapReply2 = itemTrapReply2Temp
}
else
{
itemTrapReply2 = nullLabel
}
var itemTrapReply3 : String = ""
if let itemTrapReply3Temp = oneItem["itemTrapReply3"] as? String
{
itemTrapReply3 = itemTrapReply3Temp
}
else
{
itemTrapReply3 = nullLabel
}
var itemTrapReply4 : String = ""
if let itemTrapReply4Temp = oneItem["itemTrapReply4"] as? String
{
itemTrapReply4 = itemTrapReply4Temp
}
else
{
itemTrapReply4 = nullLabel
}
finalAllItems.append(
AllItems(
itemWord:itemWord,
itemWordMeaning: itemMeaning,
itemVerb2Form: itemVerb2Form,
itemVerb3Form: itemVerb3Form,
itemDefination: itemDefination,
itemUsingInSentence: itemUsingInSentence,
itemThisWordIsReleatedWithThatWord: itemThisWordIsRelatedWithThatWord,
itemTrapReply1: itemTrapReply1,
itemTrapReply2: itemTrapReply2,
itemTrapReply3: itemTrapReply3,
itemTrapReply4: itemTrapReply4
)
)
} // FOR LOOP ENDS
} // convertReturnsInToWantedType ENDS
override var prefersStatusBarHidden: Bool {
return true
}
}
extension HomeViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//return self.dataList.count
return self.howmanyWords
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = outletForTheCollectionView.dequeueReusableCell(withReuseIdentifier: "ViewCellID", for: indexPath) as! CustomCell
cell.outletForTheViewInCell.backgroundColor = .lightGray
// word label
cell.outletForTheLabelInCell.text = self.finalAllItems[indexPath.row].itemWord
print(finalAllItems[indexPath.row].itemWord)
var allRepliesArray =
[
self.finalAllItems[indexPath.row].itemTrapReply1,
self.finalAllItems[indexPath.row].itemTrapReply2,
self.finalAllItems[indexPath.row].itemTrapReply3,
self.finalAllItems[indexPath.row].itemTrapReply4,
self.finalAllItems[indexPath.row].itemWordMeaning
]
print(allRepliesArray)
print(allRepliesArray.count)
let randomIndex1 = Int(arc4random_uniform(UInt32(allRepliesArray.count)))
cell.btnOptionA.setTitle(allRepliesArray[randomIndex1], for: .normal)
allRepliesArray = allRepliesArray.filter {$0 != allRepliesArray[randomIndex1]}
print(allRepliesArray.count)
let randomIndex2 = Int(arc4random_uniform(UInt32(allRepliesArray.count)))
cell.btnOptionB.setTitle(allRepliesArray[randomIndex2], for: .normal)
allRepliesArray = allRepliesArray.filter {$0 != allRepliesArray[randomIndex2]}
let randomIndex3 = Int(arc4random_uniform(UInt32(allRepliesArray.count)))
cell.btnOptionC.setTitle(allRepliesArray[randomIndex3], for: .normal)
allRepliesArray = allRepliesArray.filter {$0 != allRepliesArray[randomIndex3]}
let randomIndex4 = Int(arc4random_uniform(UInt32(allRepliesArray.count)))
cell.btnOptionD.setTitle(allRepliesArray[randomIndex4], for: .normal)
allRepliesArray = allRepliesArray.filter {$0 != allRepliesArray[randomIndex4]}
cell.btnOptionE.setTitle(allRepliesArray[0], for: .normal)
cell.correctReply = self.correctAnswerArray[indexPath.row]
print("cevapDogruMu: \(cevapDogruMu)")
cell.dismiss = { [weak self] str in
//Here.
if str == "true"
{
cell.outletForTheViewInCell.backgroundColor = .green
}
else
{
cell.outletForTheViewInCell.backgroundColor = .red
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let screenSize = UIScreen.main.bounds.size
return screenSize
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let index = self.outletForTheCollectionView.contentOffset.x / self.outletForTheCollectionView.frame.size.width
self.outletForThePageController.currentPage = Int(index)
//self.outletForThePageController.numberOfPages = dataList.count
self.outletForThePageController.numberOfPages = self.howmanyWords
}
class SnappingCollectionViewLayout: UICollectionViewFlowLayout {
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
guard let collectionView = collectionView else { return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) }
var offsetAdjustment = CGFloat.greatestFiniteMagnitude
let horizontalOffset = proposedContentOffset.x + collectionView.contentInset.left
let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView.bounds.size.width, height: collectionView.bounds.size.height)
let layoutAttributesArray = super.layoutAttributesForElements(in: targetRect)
layoutAttributesArray?.forEach({ (layoutAttributes) in
let itemOffset = layoutAttributes.frame.origin.x
if fabsf(Float(itemOffset - horizontalOffset)) < fabsf(Float(offsetAdjustment)) {
offsetAdjustment = itemOffset - horizontalOffset
}
})
return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
}
}
} // extension ENDS
extension MutableCollection {
/// Shuffles the contents of this collection.
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
// Change `Int` in the next line to `IndexDistance` in < Swift 4.1
let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
let i = index(firstUnshuffled, offsetBy: d)
swapAt(firstUnshuffled, i)
}
}
}
extension Sequence {
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Element] {
var result = Array(self)
result.shuffle()
return result
}
}
This is an example for the JSON return
[
{
"itemWord": "surpass",
"itemMeaning": "lorem",
"itemVerb2Form": "surpassVerb2",
"itemVerb3Form": "surpassVerb3",
"itemDefination": null,
"itemUsingInSentence": null,
"itemThisWordIsRelatedWithThatWord": null,
"itemTrapReply1": "lorem",
"itemTrapReply2": "lorem",
"itemTrapReply3": "lorem",
"itemTrapReply4": "lorem"
},
{
"itemWord": "affect",
"itemMeaning": "lorem",
"itemVerb2Form": "affectVerb2",
"itemVerb3Form": "affectVerb3",
"itemDefination": null,
"itemUsingInSentence": null,
"itemThisWordIsRelatedWithThatWord": null,
"itemTrapReply1": "lorem",
"itemTrapReply2": "lorem",
"itemTrapReply3": "lorem",
"itemTrapReply4": "lorem"
}
]
AllItems.swift file
import Foundation
class AllItems
{
var itemWord : String = "" // 1
var itemWordMeaning : String = "" // 2
var itemVerb2Form : String = "" // 3
var itemVerb3Form : String = "" // 4
var itemDefination : String = "Verb" // 5
var itemUsingInSentence: String = "" // 6
var itemThisWordIsReleatedWithThatWord : String = "" // 7
var itemTrapReply1 : String = ""
var itemTrapReply2 : String = ""
var itemTrapReply3 : String = ""
var itemTrapReply4 : String = ""
init(
itemWord:String,
itemWordMeaning:String,
itemVerb2Form:String,
itemVerb3Form:String,
itemDefination: String,
itemUsingInSentence:String,
itemThisWordIsReleatedWithThatWord: String,
itemTrapReply1: String,
itemTrapReply2: String,
itemTrapReply3: String,
itemTrapReply4: String)
{
self.itemWord = itemWord //1
self.itemWordMeaning = itemWordMeaning //2
self.itemVerb2Form = itemVerb2Form // 3
self.itemVerb3Form = itemVerb3Form // 4
self.itemDefination = itemDefination // 5
self.itemUsingInSentence = itemUsingInSentence // 6
self.itemThisWordIsReleatedWithThatWord = itemThisWordIsReleatedWithThatWord // 7
self.itemTrapReply1 = itemTrapReply1 // 8
self.itemTrapReply2 = itemTrapReply2 // 9
self.itemTrapReply3 = itemTrapReply3 // 10
self.itemTrapReply4 = itemTrapReply4 // 11
}
}
Data request from API is asynchronous. To solve your problem you can call the reloadData function when your finalAllItems variable is setted.
var finalAllItems = [AllItems]() {
didSet {
outletForTheCollectionView.reloadData()
}
}
I'm not sure, but I think you're not setting up the values in your cells.
Right now you're just seeing a bunch of gray cells, right? Maybe just one?
In the func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell, you should set up the values to be shown in the cells before returning them. All you're doing right now is setting up the background color, nothing else.
You should do something like cell.setUpData(finalAllItems[indexPath.row]) inside that function, and then in the cell class you have to create the setUpData method and do whatever you want to do with your data in the cell.
And yes, you should call outletForTheCollectionView.reloadData() every time you want to show new data.

swift - Updating several uiimageview

I have been working on this project which needs several uiimageviews which, they are in a uicollectionviewcell, to be updated based on the information on the database!
i have tried background threads but it didnt help!im wondering why the images wont update!
here is my code
func update_cells()
{
if sqlite3_prepare(self.db, "SELECT * FROM `habit_days` WHERE `habit_id` = \(self.id!)", -1, &self.stmt, nil) == SQLITE_OK
{
while(sqlite3_step(self.stmt) == SQLITE_ROW)
{
if(String(cString: sqlite3_column_text(self.stmt, 3 )) == "checked")
{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "mark")
self.day_id = self.day_id + 1
}
}else{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
self.day_id = self.day_id + 1
}
}
self.date = String(cString:sqlite3_column_text(self.stmt, 2))
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
self.lastdate = frmt.date(from: self.date!)
}
self.todayedate = Date()
}
}
any help would be appriciated
///////////////////
UPDATE
So i have changed my code to this and now i have my code working but still 1 problem :| all the cells are changing except the first one!
//
// Habit_Activity.swift
// Habit
//
// Created by shayan rahimian on 3/3/18.
// Copyright © 2018 shayan rahimian. All rights reserved.
//
import UIKit
import SQLite3
class Habit_check: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return days
}
#IBOutlet weak var des: UITextView!
#IBOutlet weak var col: UICollectionView!
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.layer.borderWidth = 1.5
cell.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
let image = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
print(indexPath.row)
image.tag = indexPath.row
cell.contentView.addSubview(image)
return cell
}
#IBAction func back(_ sender: Any) {
let back = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "habits_list") as? Habits_list
self.present(back!, animated: true, completion: nil)
}
#IBAction func check(_ sender: Any) {
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
let mystr = frmt.string(from: todayedate)
print(mystr)
if ( days_passed > 0){
sqlite3_exec(db, "INSERT INTO `habit_days`(`id`,`habit_id`,`time`,`state`) VALUES(null,\(self.id!),'\(mystr)','checked')", nil, nil, nil)
let image = self.view.viewWithTag(day_id) as? UIImageView
image?.image = UIImage(named: "mark")
days_passed = 0
day_id = day_id + 1
}
else{
self.view.makeToast("باید از اخرین تغیریرات شما ۲۴ ساعت گذشته باشد", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}
#IBOutlet weak var cell_view: UIView!
#IBAction func del(_ sender: Any) {
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
let mystr = frmt.string(from: todayedate)
if ( days_passed > 0){
sqlite3_exec(db, "INSERT INTO `habit_days`(`id`,`habit_id`,`time`,`state`) VALUES(null,\(self.id!),'\(mystr)','unchecked')", nil, nil, nil)
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
days_passed = 0
day_id = day_id + 1
}
else{
self.view.makeToast("باید از اخرین تغیریرات شما ۲۴ ساعت گذشته باشد", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}
#IBOutlet weak var name_label: UILabel!
var id : Int!
var db: OpaquePointer?
var stmt:OpaquePointer?
var name: String!
var days: Int!
var day_id = 0
var date: String!
var lastdate: Date!
var todayedate: Date!
var days_passed = 999
weak var delegate: Habits_list!
override func viewDidLoad() {
super.viewDidLoad()
cell_view.layer.borderWidth = 3
cell_view.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
cell_view.layer.cornerRadius = 10
col.layer.borderWidth = 3
col.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
col.layer.cornerRadius = 10
des.layer.borderWidth = 3
des.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
des.layer.cornerRadius = 10
get_info()
DispatchQueue.global(qos: .background).async {
self.update_cells()
if (self.lastdate != nil) {
self.days_passed = Calendar.current.dateComponents([.day], from: self.lastdate, to: self.todayedate).day!
}
}
}
func update_cells()
{
if sqlite3_prepare(self.db, "SELECT * FROM `habit_days` WHERE `habit_id` = \(self.id!)", -1, &self.stmt, nil) == SQLITE_OK
{
while(sqlite3_step(self.stmt) == SQLITE_ROW)
{
if(String(cString: sqlite3_column_text(self.stmt, 3 )) == "checked")
{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "mark")
self.day_id = self.day_id + 1
}
}else{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
self.day_id = self.day_id + 1
}
}
self.date = String(cString:sqlite3_column_text(self.stmt, 2))
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
self.lastdate = frmt.date(from: self.date!)
}
self.todayedate = Date()
}
}
func get_info()
{
let fileNameToDelete = "habits.sqlite"
var filePath = ""
// Fine documents directory on device
let dirs : [String] = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
if dirs.count > 0
{
let dir = dirs[0] //documents directory
filePath = dir.appendingFormat("/" + fileNameToDelete)
print("Local path = \(filePath)")
} else
{
print("Could not find local directory to store file")
return
}
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("user.sqlite")
if sqlite3_open(fileURL.path, &db) == SQLITE_OK
{
if sqlite3_prepare(db, "SELECT * FROM `habits` WHERE `id` = \(self.id!)", -1, &stmt, nil) == SQLITE_OK
{
while(sqlite3_step(stmt) == SQLITE_ROW){
self.name = String(cString: sqlite3_column_text(stmt, 1))
name_label.text = self.name
self.days = Int(sqlite3_column_int(stmt, 2))
}
}
}
}
}
cell with tag number 0 is not changing! but other ones are ok.
///////////////////////
UPDATE 3 (Some how solved)
i have updated my code as below, it is not what i wanted but it is a work around in some way
//
// Habit_Activity.swift
// Habit
//
// Created by shayan rahimian on 3/3/18.
// Copyright © 2018 shayan rahimian. All rights reserved.
//
import UIKit
import SQLite3
class Habit_check: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return days + 1
}
#IBOutlet weak var des: UITextView!
#IBOutlet weak var col: UICollectionView!
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.transform = CGAffineTransform(scaleX: -1, y: 1)
if indexPath.row != 0 {
cell.layer.borderWidth = 1.5
cell.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
let image = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
image.tag = indexPath.row
cell.contentView.addSubview(image)
}
return cell
}
#IBAction func back(_ sender: Any) {
let back = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "habits_list") as? Habits_list
self.present(back!, animated: true, completion: nil)
}
#IBAction func check(_ sender: Any) {
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
let mystr = frmt.string(from: todayedate)
print(mystr)
if (day_id <= days) {
if ( days_passed > 0){
sqlite3_exec(db, "INSERT INTO `habit_days`(`id`,`habit_id`,`time`,`state`) VALUES(null,\(self.id!),'\(mystr)','checked')", nil, nil, nil)
let image = self.view.viewWithTag(day_id) as? UIImageView
image?.image = UIImage(named: "mark")
days_passed = 0
day_id = day_id + 1
}
else{
self.view.makeToast("باید از اخرین تغییرات شما ۲۴ ساعت گذشته باشد", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}else{
self.view.makeToast("تعداد روز های عادت شما به پایان رسیده", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}
#IBOutlet weak var cell_view: UIView!
#IBAction func del(_ sender: Any) {
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
let mystr = frmt.string(from: todayedate)
if (day_id <= days) {
if ( days_passed > 0){
sqlite3_exec(db, "INSERT INTO `habit_days`(`id`,`habit_id`,`time`,`state`) VALUES(null,\(self.id!),'\(mystr)','unchecked')", nil, nil, nil)
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
days_passed = 0
day_id = day_id + 1
}
else{
self.view.makeToast("باید از اخرین تغیریرات شما ۲۴ ساعت گذشته باشد", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}else{
self.view.makeToast("تعداد روز های عادت شما به پایان رسیده", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}
#IBOutlet weak var name_label: UILabel!
var id : Int!
var db: OpaquePointer?
var stmt:OpaquePointer?
var name: String!
var days: Int!
var day_id = 1
var date: String!
var lastdate: Date!
var todayedate: Date!
var days_passed = 999
weak var delegate: Habits_list!
override func viewDidLoad() {
super.viewDidLoad()
get_info()
des.textAlignment = .right
des.makeTextWritingDirectionRightToLeft(self)
col.transform = CGAffineTransform(scaleX: -1, y: 1)
}
override func viewDidAppear(_ animated: Bool) {
cell_view.layer.borderWidth = 3
cell_view.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
cell_view.layer.cornerRadius = 10
col.layer.borderWidth = 3
col.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
col.layer.cornerRadius = 10
des.layer.borderWidth = 3
des.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
des.layer.cornerRadius = 10
DispatchQueue.global(qos: .background).async {
self.update_cells()
if (self.lastdate != nil) {
self.days_passed = Calendar.current.dateComponents([.day], from: self.lastdate, to: self.todayedate).day!
}
}
}
func update_cells()
{
if sqlite3_prepare(self.db, "SELECT * FROM `habit_days` WHERE `habit_id` = \(self.id!)", -1, &self.stmt, nil) == SQLITE_OK
{
while(sqlite3_step(self.stmt) == SQLITE_ROW)
{
if(String(cString: sqlite3_column_text(self.stmt, 3 )) == "checked")
{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "mark")
self.day_id = self.day_id + 1
}
}else{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
self.day_id = self.day_id + 1
}
}
self.date = String(cString:sqlite3_column_text(self.stmt, 2))
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
self.lastdate = frmt.date(from: self.date!)
}
self.todayedate = Date()
}
}
func get_info()
{
let fileNameToDelete = "habits.sqlite"
var filePath = ""
// Fine documents directory on device
let dirs : [String] = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
if dirs.count > 0
{
let dir = dirs[0] //documents directory
filePath = dir.appendingFormat("/" + fileNameToDelete)
print("Local path = \(filePath)")
} else
{
print("Could not find local directory to store file")
return
}
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("user.sqlite")
if sqlite3_open(fileURL.path, &db) == SQLITE_OK
{
if sqlite3_prepare(db, "SELECT * FROM `habits` WHERE `id` = \(self.id!)", -1, &stmt, nil) == SQLITE_OK
{
while(sqlite3_step(stmt) == SQLITE_ROW){
self.name = String(cString: sqlite3_column_text(stmt, 1))
name_label.text = self.name
self.des.text = String(cString: sqlite3_column_text(stmt, 3))
self.days = Int(sqlite3_column_int(stmt, 2))
}
}
}
}
}

UICollection View cell not removing at indexpath

I am using collection view for displaying result.I want to delete particular cell when that cell is selected. To keep record of selected cell, i am using struct.Everything is working perfectly. But when i click delete button selected cell are not getting deleted.Some other cell gets deleted. But when i go back to the previous screen and come back again ,the cell which i wanted to be deleted is actually removed. I don't know why and how this is happening?
import UIKit
import GRDBCipher
class AdvisoryViewController:
UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {
#IBOutlet weak var new_advisory_label: UILabel!
var getname=String()
var array=[String]()
var date_array=[String]()
var crop_code:String=""
var dbQueue:DatabaseQueue? = nil
var ss = [Int]()
var struct_array :[myObject] = []
var msg_stat:[oldMsg] = []
var msg_count_array=[Int]()
var msg_array=[String]()
var selected_date_array=[String]()
var srno_array=[String]()
var selected_srno_array=[String]()
#IBOutlet weak var collection_view: UICollectionView!
struct myObject
{
var date: String
var advisory:String
var status: String
var srno: String
}
struct oldMsg
{
var is_checked: Bool
}
override func viewDidLoad() {
super.viewDidLoad()
do{
let longpress1=UILongPressGestureRecognizer(target: self, action: #selector(longpress))
// longpress1.minimumPressDuration=1
collection_view.addGestureRecognizer(longpress1)
let
path=NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask,
true).first!
dbQueue = try DatabaseQueue(path: "\(path)/pest_messenger.sqlite")
try dbQueue?.inDatabase { db in
let crop_sursor = try Row.fetchCursor(db, "SELECT * FROM crop_master where crop_name='\(getname)'")
while let row = try crop_sursor.next() {
let title: String = row.value(named: "srno")
crop_code=title
}
let rows = try Row.fetchCursor(db, "SELECT distinct brief_advisory,advisory_date,srno FROM crop_insect_advisory_issued where crop_code='\(crop_code)'")
while let row = try rows.next() {
let title: String = row.value(named: "brief_advisory")
let da:String=row.value(named:"advisory_date")
let srno:Int = row.value(named:"srno")
let date_f=DateFormatter()
date_f.dateFormat="yyyy-MM-dd"
let d=date_f.date(from: da)
date_f.dateFormat="dd-MM-yyyy"
let dd=date_f.string(from: d!)
array.append(title)
date_array.append(dd)
srno_array.append("\(srno)")
}
}
for i in 0 ..< array.count
{
struct_array.append(myObject(date:date_array[i],advisory:array[i],
status:"N",srno:srno_array[i]))
}
for i in 0 ..< array.count
{
msg_stat.append(oldMsg(is_checked: false))
}
collection_view.delegate = self
collection_view.dataSource = self
}catch{
print(error)
}
}
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return array.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt
indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
"AdvisoryCollectionViewCell", for: indexPath) as!
AdvisoryCollectionViewCell
cell.msg_label.text = struct_array[indexPath.item].advisory
cell.date_label.text = struct_array[indexPath.item].date
let imagee = UIImage.init(named: "rsz_tick")
cell.check_image.image = imagee
cell.check_image.isHidden = true
if( msg_stat[indexPath.row].is_checked == false){
cell.check_image.isHidden = true
}
else if(msg_stat[indexPath.row].is_checked == true)
{
cell.check_image.isHidden = false
}
else{
}
return cell
}
func longpress(gestureRecognizer: UIGestureRecognizer)
{
let righbarButton = UIBarButtonItem(image: UIImage(named:
"rsz_delete")?.withRenderingMode(.alwaysOriginal), style:
UIBarButtonItemStyle.plain, target: self, action:
#selector(myRightTapped(sender:)))
self.navigationItem.rightBarButtonItem = righbarButton
let longpress = gestureRecognizer as! UILongPressGestureRecognizer
let state = longpress.state
let locationInview = longpress.location(in: collection_view)
var indexpath=collection_view.indexPathForItem(at: locationInview)
if(gestureRecognizer.state == UIGestureRecognizerState.began)
{
let cell = collection_view.cellForItem(at: indexpath!) as!
AdvisoryCollectionViewCell
cell.check_image.isHidden = false
msg_stat[(indexpath?.row)!].is_checked = true
ss.append((indexpath?.item)!)
print("index of deleting = \(indexpath?.item)")
msg_count_array.append((indexpath?.item)!)
msg_array.append(struct_array[(indexpath?.item)!].advisory)
selected_date_array.append(struct_array[(indexpath?.item)!].date)
selected_srno_array.append(struct_array[(indexpath?.item)!].srno)
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt
indexPath: IndexPath) {
let cell = collection_view.cellForItem(at: indexPath)
as!AdvisoryCollectionViewCell
if(!(ss.isEmpty)){
cell.check_image.isHidden = !cell.check_image.isHidden
if(cell.check_image.isHidden == true)
{
msg_stat[indexPath.row].is_checked = false
print("why removing.....")
if(!(msg_count_array.isEmpty)){
msg_count_array.remove(at: (indexPath.item))}
if(!(msg_array.isEmpty)){
msg_array.remove(at: (indexPath.item))
}
if(!(selected_srno_array.isEmpty))
{
selected_srno_array.remove(at: (indexPath.item))
}
if(!(selected_date_array.isEmpty))
{
selected_date_array.remove(at: (indexPath.item))
}
}
else{
msg_stat[indexPath.row].is_checked = true
msg_count_array.append((indexPath.item))
msg_array.append(array[(indexPath.item)])
selected_srno_array.append(struct_array[(indexPath.item)].srno)
}
}
}
func myRightTapped(sender:UIBarButtonItem!)
{
do{
for i in 0 ..< msg_count_array.count
{
struct_array.remove(at: i)
msg_stat.remove(at: i)
}
msg_count_array.removeAll()
for i in 0 ..< msg_array.count
{
var msg = msg_array[i]
var srno = selected_srno_array[i]
let
path=NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask,
true).first!
let dbQueue = try DatabaseQueue(path: "\(path)/pest_messenger.sqlite")
try dbQueue.inDatabase { db in
try db.execute("DELETE FROM crop_insect_advisory_issued where srno='\
(srno)'")
}
}
msg_array.removeAll()
array.removeAll()
date_array.removeAll()
srno_array.removeAll()
// let dbQueue = try DatabaseQueue(path: "\(path)/p_messenger.sqlite")
try dbQueue?.inDatabase { db in
let rows = try Row.fetchCursor(db, "SELECT distinct brief_advisory,advisory_date,srno FROM crop_insect_advisory_issued where crop_code='\(crop_code)'")
while let row = try rows.next() {
let title: String = row.value(named: "brief_advisory")
let da:String=row.value(named:"advisory_date")
let srno:Int = row.value(named:"srno")
let date_f=DateFormatter()
date_f.dateFormat="yyyy-MM-dd"
let d=date_f.date(from: da)
date_f.dateFormat="dd-MM-yyyy"
let dd=date_f.string(from: d!)
array.append(title)
date_array.append(dd)
srno_array.append("\(srno)")
}
}
for i in 0 ..< array.count
{
struct_array.append(myObject(date:date_array[i],advisory:array[i],
status:"N",srno:srno_array[i]))
}
for i in 0 ..< array.count
{
msg_stat.append(oldMsg(is_checked: false))
}
collection_view.reloadData()
}
catch{
print(error)
}
}
}

Create a Login Page for SKSprite Game

I am in the process of creating a game (Swift) in xcode using a number of SKScene and Sprite objects. I want to create a Scene (settings scene) that captures the player's name, email, gender etc. How can I go about this? How can I capture input from user. SKScenes do not allow input fields/values in the UI?
Thanks
You can build a custom login page that is conform with your game layout without try to rebuild in UIKit the same graphic assets.
Few days ago I've written an answer about SKSceneDelegate to communicate between the scene(SpriteKit) and the viewController (UIKit), take present this answer if you want to call other viewControllers because its the same concept of this answer..
Starting with this GameViewController we can develop some useful methods to handle the login form buttons and show some alerts:
import UIKit
import SpriteKit
class GameViewController: UIViewController, TransitionDelegate {
override func viewDidLoad() {
super.viewDidLoad()
guard let view = self.view as! SKView? else { return }
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
let scene = GameScene(size:view.bounds.size)
scene.scaleMode = .fill
scene.delegate = self as TransitionDelegate
scene.anchorPoint = CGPoint.zero
view.presentScene(scene)
}
func showAlert(title:String,message:String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default) { action in
print("handle Ok action...")
})
alertController.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
self.present(alertController, animated: true)
}
func handleLoginBtn(username:String,password:String) {
print("handleLoginBtn")
print("username is: \(username) and password: \(password)")
}
func handleFacebookBtn() {
print("handleFacebookBtn")
}
func handleTwitterBtn() {
print("handleTwitterBtn")
}
}
Then we can make our scene trying to take the advantage of SpriteKit elements:
import SpriteKit
import UIKit
protocol TransitionDelegate: SKSceneDelegate {
func showAlert(title:String,message:String)
func handleLoginBtn(username:String,password:String)
func handleFacebookBtn()
func handleTwitterBtn()
}
class GameScene: SKScene,UITextFieldDelegate {
var usernameTextField:UITextField!
var passwordTextField:UITextField!
var loginBtn:SKShapeNode!
var facebookBtn:SKShapeNode!
var twitterBtn:SKShapeNode!
override func didMove(to view: SKView) {
//bg
let bg = SKSpriteNode(imageNamed: "appleWallpaper")
addChild(bg)
bg.position = CGPoint(x:self.size.width/2,y:self.size.height/2)
//title
let title = SKLabelNode.init(fontNamed: "AppleSDGothicNeo-Bold")
title.text = "xyzGame"; title.fontSize = 25
title.fontColor = .orange
addChild(title)
title.zPosition = 1
title.position = CGPoint(x:self.size.width/2,y:self.size.height-80)
//textfields
guard let view = self.view else { return }
let originX = (view.frame.size.width - view.frame.size.width/1.5)/2
usernameTextField = UITextField(frame: CGRect.init(x: originX, y: view.frame.size.height/4.5, width: view.frame.size.width/1.5, height: 30))
customize(textField: usernameTextField, placeholder: "Enter your username")
view.addSubview(usernameTextField)
usernameTextField.addTarget(self, action:#selector(GameScene.textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
passwordTextField = UITextField(frame: CGRect.init(x: originX, y: view.frame.size.height/4.5+60, width: view.frame.size.width/1.5, height: 30))
customize(textField: passwordTextField, placeholder: "Enter your password", isSecureTextEntry:true)
view.addSubview(passwordTextField)
//buttons
let myBlue = SKColor(colorLiteralRed: 59/255, green: 89/255, blue: 153/255, alpha: 1)
loginBtn = getButton(frame: CGRect(x:self.size.width/4,y:self.size.height/2,width:self.size.width/2,height:30),fillColor:myBlue,title:"Login",logo:nil,name:"loginBtn")
addChild(loginBtn)
loginBtn.zPosition = 1
let label = SKLabelNode.init(fontNamed: "AppleSDGothicNeo-Regular")
label.text = "or connect with"; label.fontSize = 15
label.fontColor = .gray
addChild(label)
label.zPosition = 1
label.position = CGPoint(x:self.size.width/2,y:self.size.height/2-30)
let logoFb = SKSpriteNode.init(imageNamed: "facebook-icon")
logoFb.setScale(0.5)
facebookBtn = getButton(frame: CGRect(x:self.size.width/4,y:self.size.height/2-80,width:self.size.width/4.5,height:30),fillColor:myBlue,logo:logoFb,name:"facebookBtn")
addChild(facebookBtn)
facebookBtn.zPosition = 1
let myCyan = SKColor(colorLiteralRed: 85/255, green: 172/255, blue: 239/255, alpha: 1)
let logoTw = SKSpriteNode.init(imageNamed: "twitter-icon")
logoTw.setScale(0.5)
twitterBtn = getButton(frame: CGRect(x:self.size.width/2,y:self.size.height/2-80,width:self.size.width/4.5,height:30),fillColor:myCyan,logo:logoTw,name:"twitterBtn")
addChild(twitterBtn)
twitterBtn.zPosition = 1
}
func customize(textField:UITextField, placeholder:String , isSecureTextEntry:Bool = false) {
let paddingView = UIView(frame:CGRect(x:0,y: 0,width: 10,height: 30))
textField.leftView = paddingView
textField.keyboardType = UIKeyboardType.emailAddress
textField.leftViewMode = UITextFieldViewMode.always
textField.attributedPlaceholder = NSAttributedString(string: placeholder,attributes: [NSForegroundColorAttributeName: UIColor.gray])
textField.autocapitalizationType = .none
textField.autocorrectionType = .no
textField.layer.borderColor = UIColor.gray.cgColor
textField.layer.borderWidth = 0.5
textField.layer.cornerRadius = 4.0
textField.textColor = .white
textField.isSecureTextEntry = isSecureTextEntry
textField.delegate = self
}
func getButton(frame:CGRect,fillColor:SKColor,title:String = "",logo:SKSpriteNode!,name:String)->SKShapeNode {
let btn = SKShapeNode(rect: frame, cornerRadius: 10)
btn.fillColor = fillColor
btn.strokeColor = fillColor
if let l = logo {
btn.addChild(l)
l.zPosition = 2
l.position = CGPoint(x:frame.origin.x+(frame.size.width/2),y:frame.origin.y+(frame.size.height/2))
l.name = name
}
if !title.isEmpty {
let label = SKLabelNode.init(fontNamed: "AppleSDGothicNeo-Regular")
label.text = title; label.fontSize = 15
label.fontColor = .white
btn.addChild(label)
label.zPosition = 3
label.position = CGPoint(x:frame.origin.x+(frame.size.width/2),y:frame.origin.y+(frame.size.height/4))
label.name = name
}
btn.name = name
return btn
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let positionInScene = touch!.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name {
switch name {
case "loginBtn":
self.run(SKAction.wait(forDuration: 0.1),completion:{[unowned self] in
guard let delegate = self.delegate else { return }
(delegate as! TransitionDelegate).handleLoginBtn(username:self.usernameTextField.text!,password: self.passwordTextField.text!)
})
case "facebookBtn":
self.run(SKAction.wait(forDuration: 0.1),completion:{[unowned self] in
guard let delegate = self.delegate else { return }
(delegate as! TransitionDelegate).handleFacebookBtn()
})
case "twitterBtn":
self.run(SKAction.wait(forDuration: 0.1),completion:{[unowned self] in
guard let delegate = self.delegate else { return }
(delegate as! TransitionDelegate).handleTwitterBtn()
})
default:break
}
}
}
func textFieldDidChange(textField: UITextField) {
//print("everytime you type something this is fired..")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == usernameTextField { // validate email syntax
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
let result = emailTest.evaluate(with: textField.text)
let title = "Alert title"
let message = result ? "This is a correct email" : "Wrong email syntax"
if !result {
self.run(SKAction.wait(forDuration: 0.01),completion:{[unowned self] in
guard let delegate = self.delegate else { return }
(delegate as! TransitionDelegate).showAlert(title:title,message: message)
})
}
}
}
deinit {
print("\n THE SCENE \((type(of: self))) WAS REMOVED FROM MEMORY (DEINIT) \n")
}
}
Output:
Animated output:
As you can see we can handle both framework with their delegate methods, I've tested this page with iPhone 5 and iPhone 7 plus.