I created a UICollectionView named UserProfileController.
I created a UICollectionViewCell named UserProfilePhotoCell.
I created avplayer in UserProfilePhotoCell.
When you click on Avplayer the video starts.
When I click on the 1st AVPlayer on the cell,
The first, fifth, ninth cells play AVplayer.
How can I fix?
Issue Video = https://ibb.co/bMwOAe
import UIKit
import Alamofire
import AVKit
import AVFoundation
class UserProfileController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let screen = ScreenProp()
var posts = [ProfileVideo]()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Profil Detay"
collectionView?.backgroundColor = .white
collectionView?.register(UserProfileHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "headerID")
collectionView?.delegate = self
collectionView?.dataSource = self
collectionView?.register(UserProfilePhotoCell.self, forCellWithReuseIdentifier: "cellId")
veriCek()
}
var user: User?
func veriCek(){
//http post başlangıç
// LoadingOverlay.shared.showOverlay(view: UIApplication.shared.keyWindow!)
//
// guard let confirm = phoneInput.text else {return}
let defaults = UserDefaults.standard
let userID = defaults.integer(forKey: "userID")
let acToken = defaults.string(forKey: "acToken")
let parameters: Parameters = [
"userID": userID,
"acToken": acToken ?? ""
]
Alamofire.request("********************************", method: .post, parameters: parameters).validate().responseJSON { response in
switch response.result {
case .success:
print(response.data!)
if let result = response.result.value {
let json = result as! NSDictionary
print(json)
let dataArray = json["sonuclar"] as! NSArray;
print("Data items count: \(dataArray.count)")
for item in dataArray { // loop through data items
let obj = item as! NSDictionary
// let profileVideo = ProfileVideo(dictionary: obj)
// print(profileVideo.artistName)
let artistName = obj.value(forKey: "artistName") as! String
let commentlikes = obj.value(forKey: "commentlikes") as! String
let likeStatus = obj.value(forKey: "likeStatus") as! String
let name = obj.value(forKey: "name") as! String
let profilePics = obj.value(forKey: "profilePics") as! String
let time = obj.value(forKey: "time") as! String
let userID = obj.value(forKey: "userID") as! String
let username = obj.value(forKey: "username") as! String
let videoContent = obj.value(forKey: "videoContent") as! String
let videoID = obj.value(forKey: "videoID") as! String
let videoLikes = obj.value(forKey: "videoLikes") as! String
let videoName = obj.value(forKey: "videoName") as! String
let videoPath = obj.value(forKey: "videoPath") as! String
let view = obj.value(forKey: "view") as! String
let post = ProfileVideo(artistName: artistName, commentlikes: commentlikes, likeStatus: likeStatus, name: name, profilePics: profilePics, time: time, userID: userID, username: username, videoContent: videoContent, videoID: videoID, videoLikes: videoLikes, videoName: videoName, videoPath: videoPath, view: view, status: 0)
self.posts.append(post)
}
self.user = User(dictionary: json as! [String : Any])
self.navigationItem.title = self.user?.username
self.collectionView?.reloadData()
}
case .failure(let error):
print(error)
}
}
// http post bitiş
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerID", for: indexPath) as! UserProfileHeader
header.user = self.user
return header
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! UserProfilePhotoCell
var dizi = posts[indexPath.item]
print("\(indexPath.item) = \(dizi.status)")
cell.post = dizi
return cell
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
referenceSizeForHeaderInSection section: Int) -> CGSize{
return CGSize(width: view.frame.width ,height: CGFloat(screen.heightHesap(x: 246)))
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = view.frame.width
return CGSize(width: width, height: 500)
}
}
struct User {
let name: String
let username: String
let profileImageUrl: String
let follow: String
let follower: String
let videoCount: String
init(dictionary: [String: Any]) {
self.username = dictionary["username"] as! String
self.profileImageUrl = dictionary["profilePics"] as! String
self.name = dictionary["name"] as! String
self.follow = dictionary["follow"] as! String
self.follower = dictionary["follower"] as! String
self.videoCount = dictionary["videoCount"] as! String
}
}
struct ProfileVideo {
let artistName: String
let commentlikes: String
var likeStatus: String
let name: String
let profilePics: String
let time: String
let userID: String
let username: String
let videoContent: String
let videoID: String
let videoLikes: String
let videoName: String
let videoPath: String
let view: String
var status: Int
}
UserProfilePhotoCell
import UIKit
import AVKit
import AVFoundation
import Alamofire
class UserProfilePhotoCell: UICollectionViewCell {
var screen = ScreenProp()
var playerLayer = AVPlayerLayer()
var player = AVPlayer()
var moviePlayerController = AVPlayerViewController()
let defaults = UserDefaults.standard
var status = 0
let videoHeader: UIImageView = {
let imageView = UIImageView(image: #imageLiteral(resourceName: "videoHeader1"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .red
imageView.contentMode = .scaleToFill
imageView.clipsToBounds = true
return imageView
}()
let videoFooter: UIImageView = {
let imageView = UIImageView(image:#imageLiteral(resourceName: "videoFooter"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .none
imageView.contentMode = .scaleToFill
imageView.clipsToBounds = true
return imageView
}()
let clapsDeactive: UIImageView = {
let imageView = UIImageView(image: #imageLiteral(resourceName: "applause"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .none
imageView.contentMode = .scaleToFill
imageView.clipsToBounds = true
return imageView
}()
let clapsActive: UIImageView = {
let imageView = UIImageView(image: #imageLiteral(resourceName: "applause_on"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .none
imageView.contentMode = .scaleToFill
imageView.clipsToBounds = true
return imageView
}()
let comment: UIImageView = {
let imageView = UIImageView(image: #imageLiteral(resourceName: "comments"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .none
imageView.contentMode = .scaleToFill
imageView.clipsToBounds = true
return imageView
}()
let videoName: UILabel = {
let textView = UILabel()
textView.text = "Video Adı";
textView.textColor = CustomColor.white;
textView.font = CustomFont.textStyle16;
textView.textAlignment = .center
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
let userName: UILabel = {
let textView = UILabel()
textView.text = "username";
textView.textColor = CustomColor.bblack;
textView.font = CustomFont.textStyle16;
textView.textAlignment = .center
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
let location: UILabel = {
let textView = UILabel()
textView.text = "location";
textView.textColor = CustomColor.battleshipGreyTwo;
textView.font = CustomFont.textStyle16;
textView.textAlignment = .center
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
let profilePhoto: UIImageView = {
var screen1 = ScreenProp()
let imageView = UIImageView(image: #imageLiteral(resourceName: "profile_photo"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .white
imageView.contentMode = .scaleToFill
imageView.layer.cornerRadius = CGFloat(screen1.heightHesap(x: 37)/2)
imageView.clipsToBounds = true
return imageView
}()
let videoCover: UIImageView = {
var screen1 = ScreenProp()
let imageView = UIImageView(image: #imageLiteral(resourceName: "video-sample"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .white
imageView.contentMode = .scaleToFill
imageView.clipsToBounds = true
return imageView
}()
let clapsText: UILabel = {
let textView = UILabel()
textView.text = "0";
textView.textColor = CustomColor.bblack;
textView.font = CustomFont.textStyle3;
textView.textAlignment = .center
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
let commentsText: UILabel = {
let textView = UILabel()
textView.text = "0";
textView.textColor = CustomColor.bblack;
textView.font = CustomFont.textStyle3;
textView.textAlignment = .center
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
let content: UITextView = {
let textView = UITextView()
textView.text = "Donec pretium est sit amet ipsum fringilla feugiat. Aliquam erat volutpat. Maecenas scelerisque,";
textView.textColor = CustomColor.cloudyBlue;
textView.font = CustomFont.textStyle3;
textView.textAlignment = .left
textView.isEditable = false
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isScrollEnabled = false
return textView
}()
var set = 0
var ratePlayer = 0
var post: ProfileVideo? {
didSet{
print(post?.status)
if(set == 0){
// kur(str: (post?.videoPath)!)
}
videoName.text = "\(post?.artistName ?? "") - \(post?.videoName ?? "")"
userName.text = post?.username
clapsText.text = post?.videoLikes as? String
commentsText.text = post?.commentlikes
content.text = post?.videoContent
var url = URL(string: post?.profilePics ?? "")
ImageLoader.image(for: url!) { image in
self.profilePhoto.image = image
}
if(post?.likeStatus == "0"){
status = 1
self.clapsDeactive.image = UIImage(named: "applause")
}else{
status = 0
self.clapsDeactive.image = UIImage(named: "applause_on")
}
set = set + 1
}
}
func kur(str: String){
print("asdjvhsagdvjsakd")
let videoURL = URL(string: str)
// var myUrl = post.image // post.image is image url
let fileUrl = videoURL
// aPlayer = AVPlayer(URL: fileUrl as! URL)
player = AVPlayer(url: fileUrl!)
moviePlayerController.player = player
moviePlayerController.view.frame = CGRect(x:0, y:37, width:frame.size.width, height:300)
moviePlayerController.videoGravity = AVLayerVideoGravity.resizeAspectFill.rawValue
moviePlayerController.view.sizeToFit()
moviePlayerController.showsPlaybackControls = true
addSubview(moviePlayerController.view)
//moviePlayerController.player?.play()
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(videoHeader)
addSubview(videoName)
addSubview(profilePhoto)
addSubview(userName)
addSubview(location)
addSubview(videoFooter)
addSubview(clapsDeactive)
addSubview(comment)
addSubview(clapsText)
addSubview(commentsText)
addSubview(content)
addSubview(videoCover)
setup()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(like(tapGestureRecognizer:)))
clapsDeactive.isUserInteractionEnabled = true
clapsDeactive.addGestureRecognizer(tapGestureRecognizer)
let tapGestureRecognizer2 = UITapGestureRecognizer(target: self, action: #selector(playVideo(tapGestureRecognizer:)))
videoCover.isUserInteractionEnabled = true
videoCover.addGestureRecognizer(tapGestureRecognizer2)
}
func setup(){
videoHeader.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: frame.size.width, height: CGFloat(screen.heightHesap(x: 37)))
videoName.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: CGFloat(screen.heightHesap(x: 9)), paddingLeft: CGFloat(screen.widthHesap(x: 40)), paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
profilePhoto.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: CGFloat(screen.heightHesap(x: 360)), paddingLeft: CGFloat(screen.widthHesap(x: 20)), paddingBottom: 0, paddingRight: 0, width: CGFloat(screen.widthHesap(x: 37)), height: CGFloat(screen.heightHesap(x: 37)))
userName.anchor(top: profilePhoto.topAnchor, left: profilePhoto.rightAnchor, bottom: nil, right: nil, paddingTop: 0, paddingLeft: CGFloat(screen.widthHesap(x: 11)), paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
location.anchor(top: userName.bottomAnchor, left: profilePhoto.rightAnchor, bottom: nil, right: nil, paddingTop: 0, paddingLeft: CGFloat(screen.widthHesap(x: 11)), paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
videoFooter.anchor(top: topAnchor, left: nil, bottom: nil, right: rightAnchor, paddingTop: CGFloat(screen.heightHesap(x: 356)), paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: CGFloat(screen.widthHesap(x: 180)), height: CGFloat(screen.heightHesap(x: 50)))
clapsDeactive.anchor(top: videoFooter.topAnchor, left: videoFooter.leftAnchor, bottom: nil, right: nil, paddingTop: CGFloat(screen.heightHesap(x: 9)), paddingLeft: CGFloat(screen.widthHesap(x: 29)), paddingBottom: 0, paddingRight: 0, width: CGFloat(screen.widthHesap(x: 33)), height: CGFloat(screen.heightHesap(x: 28)))
comment.anchor(top: videoFooter.topAnchor, left: videoFooter.leftAnchor, bottom: nil, right: nil, paddingTop: CGFloat(screen.heightHesap(x: 15)), paddingLeft: CGFloat(screen.widthHesap(x: 110)), paddingBottom: 0, paddingRight: 0, width: CGFloat(screen.widthHesap(x: 23)), height: CGFloat(screen.heightHesap(x: 23)))
clapsText.anchor(top: videoFooter.topAnchor, left: videoFooter.leftAnchor, bottom: nil, right: nil, paddingTop: CGFloat(screen.heightHesap(x: 17)), paddingLeft: CGFloat(screen.widthHesap(x: 67)), paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
commentsText.anchor(top: videoFooter.topAnchor, left: videoFooter.leftAnchor, bottom: nil, right: nil, paddingTop: CGFloat(screen.heightHesap(x: 17)), paddingLeft: CGFloat(screen.widthHesap(x: 142)), paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
var hesap = frame.size.width - CGFloat(screen.widthHesap(x: 40))
content.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: rightAnchor, paddingTop: CGFloat(screen.heightHesap(x: 420)), paddingLeft: CGFloat(screen.widthHesap(x: 20)), paddingBottom: 0, paddingRight: CGFloat(screen.widthHesap(x: 20)), width: hesap, height: CGFloat(screen.heightHesap(x: 50)))
videoCover.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 37, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: frame.size.width, height: 300)
}
#objc func playVideo(tapGestureRecognizer: UITapGestureRecognizer)
{
kur(str: (post?.videoPath)!)
}
#objc func like(tapGestureRecognizer: UITapGestureRecognizer)
{
let userID = defaults.string(forKey: "userID")
let acToken = defaults.string(forKey: "acToken")
let parameters: Parameters = [
"userID": userID ?? "",
"acToken": acToken ?? "",
"videoID": post?.videoID ?? "",
"status": status,
"videoUserID": post?.userID ?? ""
]
Alamofire.request("***********************************", method: .post, parameters: parameters).validate().responseJSON { response in
switch response.result {
case .success:
print(response.data!)
if let result = response.result.value {
let json = result as! NSDictionary
let statusCode = json["statusCode"]
let status = json["status"]
var like = json["likeCount"] as? String
if(statusCode as? Int == 10){
print("Beğendim.")
self.post?.likeStatus = "1"
print(self.post?.likeStatus)
self.clapsDeactive.image = UIImage(named: "applause_on")
self.clapsText.text = like
}else{
print("Beğenemedim.")
self.post?.likeStatus = "0"
self.clapsDeactive.image = UIImage(named: "applause")
self.clapsText.text = like
}
}
case .failure(let error):
print(error)
}
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Just use this code for play video in the cell with expect index. It will help you a lot and for other also ,
class UserProfilePhotoCell: UICollectionViewCell {
#IBOutlet var viewForVideo: UIView!
#IBOutlet var btnPlayVideo: UIButton!
var blockVideoPlay : ((_ sender : UIButton)->())?
override func awakeFromNib() {
super.awakeFromNib()
removeSubLayerFromVideo()
self.setupMoviePlayer()
}
#IBAction func btnPlayVideoCLK(_ sender: UIButton) {
if blockVideoPlay != nil {
blockVideoPlay!(sender)
}
}
func removeSubLayerFromVideo() {
if let layerArray = viewForVideo.layer.sublayers, layerArray.isEmpty {
for layer in layerArray {
if layer.name == "\(viewForVideo.tag)" {
layer.removeFromSuperlayer()
}
}
}
}
func setupMoviePlayer(){
self.avPlayer = AVPlayer.init(playerItem: self.videoPlayerItem)
avPlayerLayer = AVPlayerLayer(player: avPlayer)
avPlayerLayer?.videoGravity = AVLayerVideoGravity.resizeAspect
avPlayerLayer?.name = "\(viewForVideo.tag)"
avPlayer?.volume = 3
avPlayer?.actionAtItemEnd = .none
avPlayerLayer?.frame = CGRect(x: 0, y: 0, width: UIScreen.width, height: UIScreen.height)
self.viewForVideo.backgroundColor = .clear
self.viewForVideo.layer.insertSublayer(avPlayerLayer!, at: 0)
// This notification is fired when the video ends, you can handle it in the method.
NotificationCenter.default.addObserver(self,
selector: #selector(self.playerItemDidReachEnd(notification:)),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: avPlayer?.currentItem)
}
func stopPlayback(){
if let player = self.avPlayer {
if player.isPlaying {
player.pause()
}
}
}
func startPlayback(){
self.avPlayer?.play()
}
// A notification is fired and seeker is sent to the beginning to loop the video again
#objc func playerItemDidReachEnd(notification: Notification) {
//let p: AVPlayerItem = notification.object as! AVPlayerItem
//p.seek(to: kCMTimeZero)
btnPlayVideo.isSelected = false
self.avPlayer?.currentItem?.seek(to: kCMTimeZero, completionHandler: { (success) in
if success {
self.avPlayer?.pause()
}
})
}
}
For View Controller use this code also you can post via var all data in the cell and from the cell, you can set URL path it works fine make sure when view Will Disappear you have to stop the player
class UserProfileController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
for cell in mediaListCollection.visibleCells {
if let cell = cell as? UserProfilePhotoCell {
cell.stopPlayback()
}
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! UserProfilePhotoCell
let url = URL(fileURLWithPath: path, isDirectory: true)
cell.videoPlayerItem = AVPlayerItem(url: url)
cell.viewForVideo.tag = indexPath.row+1
cell.blockVideoPlay = { (sender) -> Void in
sender.isSelected = !sender.isSelected
if sender.isSelected {
cell.startPlayback()
}
else {
cell.stopPlayback()
}
}
}
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if let cell = cell as? UserProfilePhotoCell {
cell.stopPlayback()
if cell.btnPlayVideo.isSelected {
cell.btnPlayVideo.isSelected = false
}
}
}
}
Also use this extension for check player is currently playing or not
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
Related
Using iOS14.0.1, Swift5.3, Xcode12.0.1,
I am desperate with this problem:
With iOS12 and iOS13, my App was working nicely.
But now with iOS14, no UIButton, no UISwitch, no segue - nothing is working in my Modal ViewController.
I have no idea what Apple changed in UIKit for this problem to occur ???? !!!!
Please help!
My Modal ViewController is presented as follows:
#objc func settingsBtnPressed(_ sender: UIButton) {
let settingsVC = SettingsViewController()
settingsVC.backDelegate = self
let navController = UINavigationController(rootViewController: settingsVC)
navController.navigationBar.barStyle = .black
navController.navigationBar.tintColor = .white
navController.navigationBar.prefersLargeTitles = true
navController.navigationBar.backgroundColor = UIColor.clear
navController.presentationController?.delegate = self
self.present(navController, animated: true)
}
class SettingsViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let cellId = "cellID"
init() {
let collectionViewFlowLayout = UICollectionViewFlowLayout()
collectionViewFlowLayout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.width, height: 1)
super.init(collectionViewLayout: collectionViewFlowLayout)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
// ...
collectionView.register(SettingsCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SettingsCollectionViewCell
cell.setup(titlesFirstSection: titlesFirstSection, iconsFirstSection: iconsFirstSection, onStatesFirstSection: onStatesFirstSection, )
return cell
}
}
class SettingsCollectionViewCell: UICollectionViewCell {
var SettingsStackView = UIStackView()
var attries: UICollectionViewLayoutAttributes!
var myContentHeight: CGFloat = 0.0
var firstSettingsSectionView: MenuSwitchListSectionView?
let elementHeight: CGFloat = 44.0
let separatorLineThickness: CGFloat = 1.0
let sectionViewBackgroundColor = ImageConverter.UIColorFromRGB(0x2C2C2E, alpha: 1.0)
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup(titlesFirstSection: [String],
iconsFirstSection: [UIImage?]?,
onStatesFirstSection: [Bool]) {
myContentHeight = UIScreen.main.bounds.height - 120
initFirstSettingsSectionView(titles: titlesFirstSection, icons: iconsFirstSection, onStates: onStatesFirstSection)
SettingsStackView = VerticalStackView(arrangedSubviews: [
UIView(),
firstSettingsSectionView! as UIView,
UIView()
], spacing: 10.0, alignment: .center )
contentView.addSubview(SettingsStackView)
contentView.isUserInteractionEnabled = true
setConstraints(nrOfItemsFirstSection: titlesFirstSection.count)
}
fileprivate func initFirstSettingsSectionView(titles: [String], icons: [UIImage?]?, onStates: [Bool]) {
firstSettingsSectionView = MenuSwitchListSectionView(frame: .zero,
elementHeight: elementHeight,
separatorLineThickness: separatorLineThickness,
backgroundColor: sectionViewBackgroundColor,
titles: titles,
icons: icons,
onStates: onStates
)
firstSettingsSectionView?.switchMutatedDelegate = self
firstSettingsSectionView?.assignDelegate()
}
fileprivate func setConstraints(nrOfItemsFirstSection: Int) {
contentView.translatesAutoresizingMaskIntoConstraints = false
SettingsStackView.translatesAutoresizingMaskIntoConstraints = false
firstSettingsSectionView?.translatesAutoresizingMaskIntoConstraints = false
SettingsStackView.anchor(top: safeAreaLayoutGuide.topAnchor, leading: contentView.leadingAnchor, bottom: nil, trailing: contentView.trailingAnchor)
let totalHeightFirstSection: CGFloat = elementHeight * CGFloat(nrOfItemsFirstSection) + separatorLineThickness * CGFloat(nrOfItemsFirstSection - 1)
firstSettingsSectionView?.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0).isActive = true
firstSettingsSectionView?.heightAnchor.constraint(equalToConstant: totalHeightFirstSection).isActive = true
firstSettingsSectionView?.widthAnchor.constraint(equalToConstant: contentView.bounds.width - 16.0).isActive = true
}
class MenuSwitchElementStackView: UIStackView {
weak var switchMutatedDelegate: SwitchMutatedDelegate?
let imgViewWidth: CGFloat = 23.0
override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(frame: CGRect, text: String, icon: UIImage?, onState: Bool, switchID: Int) {
self.init(frame: frame)
composeStackView(text: text, icon: icon, onState: onState, switchID: switchID)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func composeStackView(text: String, icon: UIImage?, onState: Bool, switchID: Int) {
// StackView properties
axis = .horizontal
alignment = .center
spacing = 23.0
var iconImgView: UIImageView?
// create Icon
if let icon = icon {
iconImgView = UIImageView()
iconImgView?.image = icon
iconImgView?.contentMode = .scaleAspectFit
}
// create Title
let titleLabel = UILabel()
titleLabel.font = AppConstants.Font.ListSectionElementTitleFont
titleLabel.text = text
titleLabel.textColor = .white
titleLabel.tintColor = .white
titleLabel.heightAnchor.constraint(equalToConstant: 19.0).isActive = true
// create choice TextLbl
let mySwitch = UISwitch()
mySwitch.tag = switchID
mySwitch.setOn(onState, animated: false)
mySwitch.addTarget(self, action: #selector(MenuSwitchElementStackView.switchChanged(_:)), for: UIControl.Event.valueChanged)
// text stackView creation
if let iconImgView = iconImgView {
addArrangedSubview(iconImgView)
}
addArrangedSubview(titleLabel)
addArrangedSubview(mySwitch)
// set Constraints
setConstraints(iconImgView, titleLabel, mySwitch)
}
#objc func switchChanged(_ mySwitch: UISwitch) {
switchMutatedDelegate?.switchChanged(isOn: mySwitch.isOn, switchID: mySwitch.tag)
}
fileprivate func setConstraints(_ iconImgView: UIImageView?, _ titleLabel: UILabel, _ mySwitch: UISwitch) {
translatesAutoresizingMaskIntoConstraints = false
iconImgView?.translatesAutoresizingMaskIntoConstraints = false
titleLabel.translatesAutoresizingMaskIntoConstraints = false
mySwitch.translatesAutoresizingMaskIntoConstraints = false
iconImgView?.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0).isActive = true
iconImgView?.widthAnchor.constraint(equalToConstant: 24.0).isActive = true
iconImgView?.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
mySwitch.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
mySwitch.leadingAnchor.constraint(equalTo: trailingAnchor, constant: -64.0).isActive = true
}
}
class MenuSwitchListSectionView: UIView {
var sectionElementsStackView: MenuSwitchListSectionWithElementsStackView?
weak var switchMutatedDelegate: SwitchMutatedDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(frame: CGRect,
elementHeight: CGFloat,
separatorLineThickness: CGFloat,
backgroundColor: UIColor,
titles: [String],
icons: [UIImage?]?,
onStates: [Bool]) {
self.init(frame: frame)
composeView(elementHeight: elementHeight, separatorLineThickness: separatorLineThickness, backgroundColor: backgroundColor, titles: titles, icons: icons, onStates: onStates)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func assignDelegate() {
self.sectionElementsStackView?.switchMutatedDelegate = switchMutatedDelegate
sectionElementsStackView?.assignDelegate()
}
fileprivate func composeView(elementHeight: CGFloat, separatorLineThickness: CGFloat, backgroundColor: UIColor, titles: [String], icons: [UIImage?]?, onStates: [Bool]) {
// create background View
let totalHeight: CGFloat = elementHeight * CGFloat(titles.count) + separatorLineThickness * CGFloat(titles.count - 1)
let backGroundView = ListSectionBackgroundView(frame: .zero, height: totalHeight, backgroundColor: backgroundColor)
// create stackView
sectionElementsStackView = MenuSwitchListSectionWithElementsStackView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: totalHeight), elementHeight: elementHeight, separatorLineThickness: separatorLineThickness, titles: titles, icons: icons, onStates: onStates)
// add background and stackView to self
addSubview(backGroundView)
addSubview(sectionElementsStackView!)
// set Constraints
translatesAutoresizingMaskIntoConstraints = false
backGroundView.translatesAutoresizingMaskIntoConstraints = false
sectionElementsStackView?.translatesAutoresizingMaskIntoConstraints = false
backGroundView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
backGroundView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
backGroundView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
backGroundView.heightAnchor.constraint(equalToConstant: totalHeight).isActive = true
sectionElementsStackView?.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
sectionElementsStackView?.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16.0).isActive = true
sectionElementsStackView?.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10.0).isActive = true
}
}
class MenuSwitchListSectionWithElementsStackView: UIStackView {
weak var switchMutatedDelegate: SwitchMutatedDelegate?
var elementStackView: MenuSwitchElementStackView?
var elements: [MenuSwitchElementStackView]?
var titles: [String]? // needed for gesture callback
override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(frame: CGRect,
elementHeight: CGFloat,
separatorLineThickness: CGFloat,
titles: [String],
icons: [UIImage?]?,
onStates: [Bool]) {
self.init(frame: frame)
self.titles = titles // needed for gesture callback
composeStackView(elementHeight: elementHeight, separatorLineThickness: separatorLineThickness, titles: titles, icons: icons, onStates: onStates)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func assignDelegate() {
if let elements = elements {
for element in elements {
element.switchMutatedDelegate = switchMutatedDelegate
}
}
}
fileprivate func composeStackView(elementHeight: CGFloat, separatorLineThickness: CGFloat, titles: [String], icons: [UIImage?]?, onStates: [Bool]) {
// stackView properties
axis = .vertical
alignment = .leading
spacing = 0.0
// create stackView elements
elements = (0..<titles.count).map { (idx) -> MenuSwitchElementStackView in
if icons?.count ?? 0 > 0 {
elementStackView = MenuSwitchElementStackView(frame: .zero, text: titles[idx], icon: icons?[idx], onState: onStates[idx], switchID: idx)
} else {
elementStackView = MenuSwitchElementStackView(frame: .zero, text: titles[idx], icon: nil, onState: onStates[idx], switchID: idx)
}
elementStackView?.isUserInteractionEnabled = true
elementStackView?.tag = idx
return elementStackView!
}
var singleLines = [UIView]()
let lineThickness: CGFloat = separatorLineThickness
// compose the stackView
if let elements = elements {
for (idx, view) in elements.enumerated() {
// add element to stackView
addArrangedSubview(view)
if idx < titles.count - 1 {
// add single Line to stackView
let singleLineView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: lineThickness))
singleLineView.backgroundColor = ImageConverter.UIColorFromRGB(0x606060, alpha: 1.0)
singleLines.append(singleLineView)
addArrangedSubview(singleLineView)
}
}
}
// set constraints
translatesAutoresizingMaskIntoConstraints = false
if let elements = elements {
for (idx, element) in elements.enumerated() {
element.translatesAutoresizingMaskIntoConstraints = false
element.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
element.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
element.heightAnchor.constraint(equalToConstant: elementHeight).isActive = true
if idx < titles.count - 1 {
singleLines[idx].translatesAutoresizingMaskIntoConstraints = false
singleLines[idx].topAnchor.constraint(equalTo: element.bottomAnchor).isActive = true
singleLines[idx].heightAnchor.constraint(equalToConstant: lineThickness).isActive = true
if icons?.count ?? 0 > 0 {
if let _ = icons?[idx] {
singleLines[idx].leadingAnchor.constraint(equalTo: leadingAnchor, constant: 39.0).isActive = true
}
} else {
singleLines[idx].leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
}
singleLines[idx].trailingAnchor.constraint(equalTo: trailingAnchor, constant: 9.0).isActive = true
}
}
}
}
}
class ListSectionBackgroundView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(frame: CGRect, height: CGFloat = 60.0, backgroundColor: UIColor) {
self.init(frame: frame)
composeView(height: height, backgroundColor: backgroundColor)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func composeView(height: CGFloat, backgroundColor: UIColor) {
// View properties
self.backgroundColor = backgroundColor
self.layer.cornerRadius = 10.0
self.layer.masksToBounds = true
self.clipsToBounds = true
// set Constraints
setConstraints(height)
}
fileprivate func setConstraints(_ height: CGFloat) {
self.translatesAutoresizingMaskIntoConstraints = false
self.heightAnchor.constraint(equalToConstant: height).isActive = true
}
}
I finally found a solution.
It was the UIView-extension "anchor" in my code that no longer works under iOS14 for some reason.
Here I describe the problem more precisely...
Therefore, if I use the extension and do the following - then any UIControls in my ViewHierarchy do not work (i.e. no target-actions, switch-didChanges, etc will no longer kick-in)
SettingsStackView.anchor(top: safeAreaLayoutGuide.topAnchor, leading: contentView.leadingAnchor, bottom: contentView.bottomAnchor, trailing: contentView.trailingAnchor)
However, if I do it without the UIView-extension, then everything works fine:
SettingsStackView.translatesAutoresizingMaskIntoConstraints = false
SettingsStackView.topAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.topAnchor).isActive = true
SettingsStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
SettingsStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
SettingsStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
Maybe somebody can tell me why this new behaviour came up with iOS14 ???
all, this code does not throw errors now but the screen is blank. I am trying to create a simple calculator. user will input numbers into 3 separate UIText fields, push a button and a UILabel would give answer. I know i do not have labels yet. i first built a container to hold text fields but then my "CalculateTapped" could not see the textFields as variables.
Question. 1 why is my screen now black?
Question. 2. why could i not get CalculateTapped to read UIText fields from my lazy var "" view earlier?
If anyone has any input i would greatly appreciate it. trying to get away from storyboards.
import UIKit
class PitchLineVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view = UIView()
()
view.backgroundColor = .white
view.anchor(top: view.topAnchor, left: view.leftAnchor,bottom: view.bottomAnchor, right: view.rightAnchor);
configureNavigationBar()
// looks for keyboard instance
NotificationCenter.default.addObserver(self, selector: #selector(PitchLineVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(PitchLineVC.keyboarWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
// keeps screen from rotating
override var shouldAutorotate: Bool {
return false
}
// Add text fields for user input to calculate pitch
private lazy var areaTxt: UITextField! = {
let area = UITextField()
area.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: -100).isActive = true
area.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -300).isActive = true
area.placeholder = "Bar Area"
area.textAlignment = .center
area.borderStyle = UITextField.BorderStyle.line
area.backgroundColor = UIColor.white
area.textColor = UIColor.black
area.keyboardType = UIKeyboardType.decimalPad
// view.addSubview(area)
return(area)
}()
private lazy var areaTop: UITextField! = {
let area = UITextField()
area.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
area.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -200).isActive = true
area.placeholder = "Top Area of Bar"
area.textAlignment = .center
area.borderStyle = UITextField.BorderStyle.line
area.backgroundColor = UIColor.white
area.textColor = UIColor.black
area.keyboardType = UIKeyboardType.decimalPad
// view.addSubview(area)
return(area)
}()
private lazy var lineLength: UITextField! = {
let line = UITextField()
line.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: -100).isActive = true
line.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -300).isActive = true
// line.anchor(top: view.bottomAnchor, paddingTop: -80,width: 100, height: 35)
line.placeholder = "Line Length"
line.textAlignment = .center
line.borderStyle = UITextField.BorderStyle.line
line.backgroundColor = UIColor.white
line.textColor = UIColor.black
line.keyboardType = UIKeyboardType.decimalPad
// view.addSubview(line)
return (line)
}()
#objc func CalculateTapped(){
print("Button Tapped")
let AreaTotal = Double(areaTxt.text!)
let AreaTop = Double(areaTop.text!)
let Line = Double(lineLength.text!)
if AreaTotal != nil && AreaTop != nil && Line != nil{
let LineMove = -(((AreaTotal! / 2) - AreaTop!) / Line!)
movepitchline.text = NSString(format: "%.3f", LineMove) as String
}
}
func addCalculateButton(){
let Calculate = UIButton()
Calculate.addTarget(self, action: #selector(CalculateTapped), for: .touchUpInside)
Calculate.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: -100).isActive = true
Calculate.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -400).isActive = true
Calculate.anchor(top: view.bottomAnchor, paddingTop: -80,
width: 100, height: 35)
view.addSubview(Calculate)
}
let movepitchline: UILabel = {
let label = UILabel()
label.textAlignment = .right
label.frame = CGRect(x: 10, y: 380, width: 220, height: 35)
label.text = "Move Pitch:"
label.font = UIFont.boldSystemFont(ofSize: 23)
label.textColor = .black
return label
}()
// When keyboard displays the UIView shift up
#objc func keyboardWillShow(notification: NSNotification) {
guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
// if keyboard size is not available for some reason, dont do anything
return
}
// move the root view up by the distance of keyboard height
self.view.frame.origin.y = 150 - keyboardSize.height
}
#objc func keyboarWillHide(notification: NSNotification){
self.view.frame.origin.y = 0//\\100 + keyboardSize.height
}
// select outside text box to dismiss selection
#objc func handleDismiss(notification: NSNotification) {
dismiss(animated: true, completion: nil)
}
func configureNavigationBar() {
navigationController?.navigationBar.barTintColor = .appBlue
navigationController?.navigationBar.barStyle = .black
navigationItem.title = "Pass Pitch and Diameters"
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "Home_2x").withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(handleDismiss))
}
}
import UIKit
class PitchLineVC: UIViewController {
lazy var pitchlogoView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.clipsToBounds = true
iv.image = #imageLiteral(resourceName: "PITCH LINE")
return iv
}()
lazy var areaTxt: UITextField! = {
let tf = UITextField()
tf.placeholder = "Bar Area"
tf.textAlignment = .center
tf.borderStyle = UITextField.BorderStyle.line
tf.backgroundColor = UIColor.white
tf.textColor = UIColor.black
tf.keyboardType = UIKeyboardType.decimalPad
return(tf)
}()
lazy var areaTop: UITextField! = {
let tf = UITextField()
tf.placeholder = "Top Area of Bar"
tf.textAlignment = .center
tf.borderStyle = UITextField.BorderStyle.line
tf.backgroundColor = UIColor.white
tf.textColor = UIColor.black
tf.keyboardType = UIKeyboardType.decimalPad
return(tf)
}()
lazy var lineLength: UITextField! = {
let tf = UITextField()
tf.placeholder = "Line Length"
tf.textAlignment = .center
tf.borderStyle = UITextField.BorderStyle.line
tf.backgroundColor = UIColor.white
tf.textColor = UIColor.black
tf.keyboardType = UIKeyboardType.decimalPad
return (tf)
}()
lazy var movepitchline1: UILabel = {
let lb = UILabel()
lb.textAlignment = .right
lb.frame = CGRect(x: 10, y: 380, width: 220, height: 35)
lb.text = "Move Pitch: + is up, - is down"
lb.textAlignment = .center
lb.font = UIFont.boldSystemFont(ofSize: 23)
lb.textColor = .black
return (lb)
}()
lazy var movepitchline: UILabel = {
let lb = UILabel()
lb.textAlignment = .right
lb.frame = CGRect(x: 10, y: 380, width: 220, height: 35)
lb.text = ""
lb.textAlignment = .center
lb.font = UIFont.boldSystemFont(ofSize: 23)
lb.textColor = .black
return (lb)
}()
let calculateButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor.init(red: 48/255, green: 173/255, blue: 99/255, alpha: 1)
button.layer.cornerRadius = 25.0
button.tintColor = UIColor.white
button.layer.shadowColor = UIColor.darkGray.cgColor
button.layer.shadowRadius = 6
button.layer.shadowOpacity = 0.7
button.layer.shadowOffset = CGSize(width: 0, height: 0)
button.setTitle("Calculate", for: .normal)
button.titleLabel?.font = UIFont(name: "Copperplate", size: 22)
button.addTarget(self, action: #selector(handleCalculate), for: .touchUpInside)
return button
}()
#objc func handleDismiss(notification: NSNotification) {
dismiss(animated: true, completion: nil)
}
//sets trigger for keyboard dismiss
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
super.touchesBegan(touches, with: event)
}
// Mark: Init
override func viewDidLoad() {
super.viewDidLoad()
configureNavigationBar()
configureViewComponent()
// looks for keyboard instance
NotificationCenter.default.addObserver(self, selector: #selector(PitchLineVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(PitchLineVC.keyboarWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
// keeps screen from rotating
override var shouldAutorotate: Bool {
return false
}
// Mark: Selectors
#objc func handleCalculate()
{
print("calculate")
guard let AreaTotal = Double(areaTxt.text!) else {return}
guard let AreaTop = Double(areaTop.text!) else {return}
guard let Line = Double(lineLength.text!) else {return}
if AreaTotal != 0 && AreaTop != 0 && Line != 0{
let LineMove = -(((AreaTotal / 2) - AreaTop) / Line)
print(LineMove)
movepitchline.text = NSString(format: "%.3f", LineMove) as String
} else{
print("Error in fields, please check entry")
}
}
func configureViewComponent(){
view.backgroundColor = .white
view.addSubview(pitchlogoView)
pitchlogoView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 120, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 250, height: 110)
view.addSubview(areaTxt)
areaTxt.anchor(top: pitchlogoView.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 15, paddingLeft: 80, paddingBottom: 0, paddingRight: 80, width: 0, height: 30)
view.addSubview(areaTop)
areaTop.anchor(top: areaTxt.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 20, paddingLeft: 80, paddingBottom: 0, paddingRight: 80, width: 0, height: 30)
view.addSubview(lineLength)
lineLength.anchor(top: areaTop.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 20, paddingLeft: 80, paddingBottom: 0, paddingRight: 80, width: 0, height: 30)
view.addSubview(calculateButton)
calculateButton.anchor(top: lineLength.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 30, paddingLeft: 32, paddingBottom: 0, paddingRight: 32, width: 0, height: 50)
view.addSubview(movepitchline1)
movepitchline1.anchor(top: calculateButton.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 10, paddingLeft: 32, paddingBottom: 0, paddingRight: 32, width: 0, height: 40)
view.addSubview(movepitchline)
movepitchline.anchor(top: movepitchline1.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 10, paddingLeft: 32, paddingBottom: 0, paddingRight: 32, width: 0, height: 40)
}
// When keyboard displays the UIView shift up
#objc func keyboardWillShow(notification: NSNotification) {
guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
// if keyboard size is not available for some reason, dont do anything
return
}
// move the root view up by the distance of keyboard height
self.view.frame.origin.y = 165 - keyboardSize.height
}
#objc func keyboarWillHide(notification: NSNotification){
self.view.frame.origin.y = 0
}
// select outside text box to dismiss selection
func configureNavigationBar() {
navigationController?.navigationBar.barTintColor = .appBlue
navigationController?.navigationBar.barStyle = .black
navigationItem.title = "Pass Pitch and Diameters"
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "Home_2x").withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(handleDismiss))
}
}
fileprivate lazy var netTipWindow:UIWindow = {
let window = UIWindow(frame: CGRect(x: 0, y: topMargins, width: UIScreenW, height: realheight))
window.backgroundColor = .clear
window.windowLevel = .alert
window.isHidden = false
window.rootViewController = UIViewController()
window.rootViewController?.view.addSubview(self)
frame = CGRect(x: 0, y: -(topMargins + realheight), width: UIScreenW, height: realheight)
return window
}()
My Code works well in ios 12, but it works like the picture.
Also, I tried this code, it makes no difference
fileprivate lazy var netTipWindow:UIWindow = {
let window = UIWindow(frame: CGRect(x: 0, y: topMargins, width: UIScreenW, height: realheight))
window.backgroundColor = .clear
window.windowLevel = .alert
window.isHidden = false
if #available(iOS 13, *) {
window.addSubview(self)
} else {
window.rootViewController = UIViewController()
window.rootViewController?.view.addSubview(self)
}
frame = CGRect(x: 0, y: -(topMargins + realheight), width: UIScreenW, height: realheight)
return window
}()
iOS 13 status bar
this code....
- (BOOL)prefersStatusBarHidden {
if (#available(iOS 13.0, *)) {
// safearea iPhone x, xr ..
if ([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0) {
return NO;
}
else {
return YES;
}
}
else {
return NO;
}
}
I have created a Swift framework that creating a button programmatically, and the action of the button is showing a webView and close it, my framework works fine in Swift project but in Objective C it just create button but it is not taking action and does not show my webView,
Note: I am getting the button configuration from server via JSON using SwiftyJSON
below is the my Swift Class in addition to SwiftyJSON in the framework project
import Foundation
import UIKit
import WebKit
#objc public class predictionButton : NSObject {
public override init(){
}
var buttonConfigApi = "XXXXXXXXX"
var buttonTextColor = String()
var buttonText = String()
var buttonBackgroundColor = String()
var buttonVisibility = Bool()
var indexURL = String()
var authURL = String()
var module = String()
var buttonAlignment = String()
var globalURL = String()
var webViewX = CGFloat()
var webViewY = CGFloat()
var webViewXiWidth = CGFloat()
var webViewHeight = CGFloat()
#objc public var globalView = UIView()
var parseFlag = Bool()
var buttonAlignmentValue = String()
#objc public func addButtonPredict(view: UIView, phone: String, token: String){
parseJSON()
sleep(5)
var phonTok = "{'a':\(phone),'b':\(token)}"
let utf8str = phonTok.data(using: String.Encoding.utf8)
let data = (phonTok).data(using: String.Encoding.utf8)
let base64 = data!.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
var finalURL = String()
self.globalView = view
finalURL = "\(self.indexURL)?d=\(base64)"
self.globalURL = finalURL
let button = UIButton(frame: buttonPosition(view: view, alignValue: buttonAlignment))
print((self.globalURL))
button.backgroundColor = hexStringToUIColor(hex: self.buttonBackgroundColor)
print("global color value \(buttonBackgroundColor)")
button.setTitle("\(self.buttonText)", for: .normal)
button.setTitleColor(hexStringToUIColor(hex: self.buttonTextColor), for: .normal)
let buttonFontSize = 15
let buttonTitleSize = (buttonText as NSString).size(withAttributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: CGFloat(buttonFontSize + 1))])
button.frame.size.height = buttonTitleSize.height * 2
button.frame.size.width = buttonTitleSize.width * 1.5
view.addSubview(button)
button.tag = 5
button.addTarget(self, action: #selector(nest), for: .touchUpInside)
}
#objc func nest (){
let frame = webViewposition(view: self.globalView)
let webView = WKWebView(frame: frame)
webView.load(NSURLRequest(url: NSURL(string: globalURL)! as URL) as URLRequest)
webView.contentMode = .scaleAspectFit
webView.tag = 100
if let viewWithTag = self.globalView.viewWithTag(100) {
viewWithTag.removeFromSuperview()
}else{
print("No!")
self.globalView.addSubview(webView)
}
}
#objc public func parseJSON(){
print("flag")
let requestURL: NSURL = NSURL(string: buttonConfigApi)!
let urlRequest: URLRequest = URLRequest(url: requestURL as URL)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest as URLRequest) {
(data, response, error) -> Void in
if data != nil {
do
{
let readableJSON = try JSON(data: data!, options: JSONSerialization.ReadingOptions.mutableContainers)
let Name = readableJSON["data"]["buttonText"].stringValue as String!
let buttonTextColor = readableJSON["data"]["buttonTextColorCode"].stringValue as String!
let buttonBackgroundColorCode = readableJSON["data"]["buttonBackgroundColorCode"].stringValue as String!
let visibility = readableJSON["data"]["visibility"].boolValue
let indexURL = readableJSON["data"]["indexURL"].stringValue as String!
let authURL = readableJSON["data"]["authURL"].stringValue as String!
let module = readableJSON["data"]["module"].stringValue as String!
let alignment = readableJSON["data"]["alignment"].stringValue as String!
self.buttonText = Name!
self.buttonTextColor = buttonTextColor!
self.buttonBackgroundColor = buttonBackgroundColorCode!
self.buttonAlignment = self.alignText(text: alignment!)
self.indexURL = indexURL!
self.authURL = authURL!
self.module = module!
print("\(Name!) \n \(buttonTextColor!) \n \(buttonBackgroundColorCode!) \n \(indexURL!) \n \(alignment!)")
print("done")
print("Color value:\(buttonBackgroundColorCode!)")
} catch {
print(error)
}
}
}
task.resume()
}
#objc func alignText (text: String) -> String {
var alignText = String()
let newString = text.replacingOccurrences(of: "_", with: "",
options: .literal, range: nil)
return newString.lowercased()
}
#objc func hexStringToUIColor (hex:String) -> UIColor {
var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
if (cString.hasPrefix("#")) {
cString.remove(at: cString.startIndex)
}
if ((cString.count) != 6) {
print("became gray")
return UIColor.gray
}
var rgbValue:UInt32 = 0
Scanner(string: cString).scanHexInt32(&rgbValue)
return UIColor(
red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
alpha: CGFloat(1.0)
)
}
#objc func webViewposition(view: UIView) -> CGRect {
var frame = CGRect()
if UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft {
frame = CGRect(x: (view.frame.width) - (view.frame.width / 4) - 120 , y: 20 , width: view.frame.width / 3 , height: view.frame.height - 60 )
} else if UIDevice.current.orientation == UIDeviceOrientation.landscapeRight {
frame = CGRect(x: (view.frame.width) - (view.frame.width / 4) - 120, y: 20 , width: view.frame.width / 3 , height: view.frame.height - 60 )
} else if UIDevice.current.orientation == UIDeviceOrientation.portrait {
frame = CGRect(x: 0, y: 110, width: view.frame.width, height: view.frame.height - 60 )
} else if UIDevice.current.orientation == UIDeviceOrientation.portraitUpsideDown {
frame = CGRect(x: 0, y: 100, width: view.frame.width, height: view.frame.height - 60 )
}
return frame
}
#objc func buttonPosition(view: UIView, alignValue: String)-> CGRect {
var position = CGRect()
switch (alignValue){
case "lefttop":
print("button top left")
position = CGRect(x: 25, y: 50, width: 100, height: 100)
case "righttop":
print("button top right")
position = CGRect(x: view.frame.width - 150, y: 50, width: 100, height: 100)
case "letbottom":
print("button bottom left")
position = CGRect(x: 25, y: view.frame.height - 150, width: 100, height: 100)
case "rightbottom":
print("button bottom right")
position = CGRect(x: view.frame.width - 25, y: view.frame.height - 150, width: 100, height: 100)
default:
position = CGRect(x: 25, y: 50, width: 100, height: 100)
}
return position
}
}
extension UIColor {
convenience init(red: Int, green: Int, blue: Int) {
assert(red >= 0 && red <= 255, "Invalid red component")
assert(green >= 0 && green <= 255, "Invalid green component")
assert(blue >= 0 && blue <= 255, "Invalid blue component")
self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) /
255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
}
convenience init(rgb: Int) {
self.init(
red: (rgb >> 16) & 0xFF,
green: (rgb >> 8) & 0xFF,
blue: rgb & 0xFF
)
}
}
extension String {
var numberValue:NSNumber? {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter.number(from: self)
}
}
and I have created a Objective-C and add the built framework in it and its .m file code is below :
#import "ViewController.h"
#import myFrameWork;
#import <myFrameWork/myFrameWork-Swift.h>
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
predictionButton *btn = [[predictionButton alloc] init];
[btn addButtonPredictWithView:self.view phone:#"XXXXXXX"
token:#"XXXXXXXXXXXXXXXXXXXXXXXXXXX"];
}
#end
Note: this framework works fine in Swift project
Here is working swift code:
import UIKit
import myFrameWork
import WebKit
class ViewController: UIViewController {
var button = predictionButton()
override func viewDidLoad() {
super.viewDidLoad()
button.addButtonPredict(view: self.view, phone: "XXXXXXXXXX", token: "XXXXXXXXXXXXXXXXXXXXXXXXX")
}
I'm trying to make a tile based game similar to the board game memory. I want the tiles which are UiViews to flip when they are pressed a the picture gets show. Is it possible to do this? I've been looking but all seems to show methods for transitions between views.
You can use this class to do a flip like animation on tap.
class FlippingView : UIView
{
var frontView : UIImageView!
var backView : UIImageView!
var isAnimating : Bool = false
override init(frame: CGRect) {
super.init(frame: frame)
frontView = UIImageView(frame: CGRectMake(0, 0, frame.size.width, frame.size.height))
backView = UIImageView(frame: frontView.frame)
self.addSubview(frontView)
self.addSubview(backView)
self.backView.hidden = true
let tapRecognizer = UITapGestureRecognizer(target: self, action: "flip")
self.addGestureRecognizer(tapRecognizer)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func flip()
{
if isAnimating {
return
}
isAnimating = true
if (backView.hidden)
{
frontView.layer.transform = CATransform3DMakeRotation(0, 0, 0, 0)
self.backView.layer.transform = CATransform3DMakeRotation(3.14/2, 0, 1, 0)
self.backView.hidden = false
UIView.animateKeyframesWithDuration(2, delay: 0, options: nil, animations: {
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.5, animations: {
self.frontView.layer.transform = CATransform3DMakeRotation(3.14/2, 0, 1, 0)
})
UIView.addKeyframeWithRelativeStartTime(0.5, relativeDuration: 0.5, animations: {
self.backView.layer.transform = CATransform3DMakeRotation(3.14, 0, 1, 0)
})
}, completion: { (finished) -> Void in
self.isAnimating = false
self.frontView.hidden = true
})
}
else
{
backView.layer.transform = CATransform3DMakeRotation(3.14, 0, 1, 0)
self.frontView.layer.transform = CATransform3DMakeRotation(3.14/2, 0, 1, 0)
self.frontView.hidden = false
UIView.animateKeyframesWithDuration(2, delay: 0, options: nil, animations: {
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.5, animations: {
self.backView.layer.transform = CATransform3DMakeRotation(-3.14/2, 0, 1, 0)
})
UIView.addKeyframeWithRelativeStartTime(0.5, relativeDuration: 0.5, animations: {
self.frontView.layer.transform = CATransform3DMakeRotation(0, 0, 1, 0)
})
}, completion: { (finished) -> Void in
self.isAnimating = false
self.backView.hidden = true
})
}
}
}
You can use it like this
override func viewDidLoad() {
flippingView = FlippingView(frame: CGRectMake(100, 100, 100, 100))
flippingView.frontView.image = UIImage(named: "1.png")
flippingView.backView.image = UIImage(named: "2.png")
self.view.addSubview(flippingView)
}