I have two classes CustomSwipOut which is a subclass of UIView and ViewController subclass of UIViewController. The callback method of delegate is not firing in ViewController class from didSelectRowAtIndexPath delegate method of table view defined in CustomSwipeOut. I have done optional binding in ViewController class as var a = CustomSwipeOut(); a.delegate = ViewController()
protocol SendIndexDelegate{
func sendIndex(Int);
}
class CustomSwipeOut: UIView , UITableViewDataSource , UITableViewDelegate {
var label: UILabel = UILabel()
var myNames = ["item1","item2","item3"]
var delegate : SendIndexDelegate?
override init()
{
super.init()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addCustomView()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addCustomView()
{
//add blank subview to the view
var blankView : UIView = UIView(frame: CGRectMake(0, 0, 300, 100))
blankView.backgroundColor = UIColor.greenColor()
self.addSubview(blankView)
//creating a tableview programmatically
var tblView : UITableView = UITableView()
tblView.frame = CGRectMake(0, 100, 300, 200)
self.addSubview(tblView)
tblView.delegate = self
tblView.dataSource = self
tblView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "myCell")
}
//pragma mark- table view data source methods
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("myCell") as UITableViewCell
cell.textLabel?.text = self.myNames[indexPath.row]
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.myNames.count
}
//pragma mark - table view delegate methods
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var row = indexPath.row
if let temp = self.delegate {
delegate?.sendIndex(row)
}else{
println("optional value contains nill value")
}
}
//ViewController Class
class ViewController: UIViewController , SendIndexDelegate {
var myView :UIView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var a = CustomSwipeOut()
a.delegate = ViewController()
let rect: CGRect = CGRect (x: self.view.frame.size.width, y :50 , width: self.view.frame.size.width-100, height: self.view.frame.size.height-100)
self.myView = CustomSwipeOut(frame : rect )
self.view.addSubview(self.myView)
//optional chaining
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func showSideMenu() {
UIView.animateWithDuration(0.2, animations:{
self.myView.frame = CGRectMake(100, 50,self.view.frame.size.width-100,self.view.frame.size.height-100)
} )
}
//delegate method
func sendIndex(row : Int)
{
switch row {
case 0:
println("index o clicked")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("MoneySum") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
println("index 2 clicked")
...
default:
println("no index")
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let rect: CGRect = CGRect (x: self.view.frame.size.width, y :50 , width: self.view.frame.size.width-100, height: self.view.frame.size.height-100)
var a = CustomSwipeOut(frame : rect)
a.delegate = self
self.myView = a
self.view.addSubview(self.myView)
//optional chaining
}
Related
Objective
When the user clicks on any of the 3 blue buttons, all buttons change to the same color.
Note: this is an abstraction of a shared progress view problem, it's therefore important that only one UIView is shared (or mimicked) across my three rows
Here is a compilable Swift project:
import UIKit
class ToggleButton: UIButton {
var connectedView: UIView?
func onPress() {
self.isHidden = true
self.connectedView?.isHidden = false
}
}
class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView = UITableView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
var myView: UIView? = nil
var toggleBtn: ToggleButton? = nil
override func viewDidLoad() {
self.setupTableView()
}
fileprivate func setupTableView() {
self.tableView.dataSource = self
self.tableView.delegate = self
self.tableView.backgroundColor = UIColor.white
self.tableView.isOpaque = true
self.view.addSubview(self.tableView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "CellIdentifier")
let frame = CGRect(x: 10, y: 10, width: 30, height: 30)
if let view = self.myView, let btn = self.toggleBtn {
cell.addSubview(view)
cell.addSubview(btn)
} else {
let myView = UIView(frame: frame)
myView.backgroundColor = UIColor.green
myView.isHidden = true
cell.addSubview(myView)
let toggleBtn = ToggleButton(frame: frame)
toggleBtn.backgroundColor = UIColor.blue
toggleBtn.addTarget(self, action: #selector(onPress), for: .touchUpInside)
toggleBtn.connectedView = myView
cell.addSubview(toggleBtn)
}
return cell
}
#objc func onPress(_ sender: Any) {
if let button = sender as? ToggleButton {
button.onPress()
}
}
}
Any help appreciated.
The concept of UITableViewCell is made to be very independent each other.
So the only thing you can do it having a bool flag in your ViewController, then you init your 3 cells with this flags.
And finally each time the button is pressed you toggle the flag en reload your tableView.
I have a UIViewController with a header subview and a UITableView.
My tableView with its custom cells works perfectly when I implement it on a UITableView class, but once I try to imbed it in my UIViewController, I get the tableview frame that I see based on the different background color but it doesn't get populated with my custom cell.
My print statement in tableview (...cellForRowAtIndexPath ..) doesn't print anything, it's as if the function is not called.
I'm not sure what I'm doing wrong, any help is much appreciated!
import UIKit
class ProfileViewController: UIViewController , UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView!
var header: UIView!
var userName: UILabel!
var userImage: UIImageView!
var dataDict : NSDictionary!
var cellArray: NSArray!
var friends = [Friends]()
init(dataDict: NSDictionary , nibName: String?, bundle: NSBundle?){
super.init(nibName: nibName, bundle: bundle)
self.dataDict = dataDict
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
cellArray = dataDict?.objectForKey("data") as! NSArray
tableView.delegate = self
tableView.dataSource = self
header = UIView(frame: CGRectZero)
header.backgroundColor = UIColor( red:77/255.0, green:255/255.0, blue:195/255.0, alpha:1.0)
userName = UILabel(frame: CGRectZero)
userName.textAlignment = .Left
userName.text = "Nachwa El khamlichi"
userName.textColor = UIColor.blackColor()
userName.frame = CGRectMake(10, 100, self.view.frame.width/2, 40)
userImage = UIImageView(frame: CGRectZero)
userImage.frame = CGRectMake(10, 30, 80, 80)
tableView.contentInset = UIEdgeInsets(top: 300, left: 0, bottom: 0, right: 0)
tableView.backgroundColor = UIColor.orangeColor()
tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine
self.view.addSubview(header)
self.view.addSubview(userName)
self.view.addSubview(userImage)
self.view.addSubview(tableView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print(cellArray.count)
let cell = tableView.dequeueReusableCellWithIdentifier( NSStringFromClass(Cell), forIndexPath: indexPath) as! Cell
let friendName = cellArray[indexPath.row]["name"] as? String
let avatarId = cellArray[indexPath.row]["id"] as? String
friends.append(Friends(name: friendName!, avatarId: avatarId!))
cell.friend?.name = friendName
cell.friend = friends[indexPath.row]
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 40
}
}
I think you forget to add
tableView = UITableView(frame: UIScreen.mainScreen().bounds, style: UITableViewStyle.Plain)
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(self.tableView)
at the same time you forget to add frame
header = UIView(frame: CGRectZero)
header.frame = CGRectMake(10, 100, self.view.frame.width/2, 40)
header.backgroundColor = UIColor( red:77/255.0, green:255/255.0, blue:195/255.0, alpha:1.0)
OPtion-2
if every thing is fine check once
your cellArray contains data available or not`,
option-3
after this line add this
self.view.addSubview(self.tableView)
tableView.reloadData()
I am trying to custom a UIView but when I call it, the outlets of custom view always nil, and awakeFromNib() never called, too. Here my CustomView:
class DropdownMenuView: UIView {
//MARK: Outlets
#IBOutlet var view: DropdownMenuView!
#IBOutlet weak var fadeView: UIView!
#IBOutlet weak var tableView: UITableView!
var selection:Selection = .Default
var iconType:IconType = .Default
var menuTitles:[String] = []
var cellHeight:CGFloat = 44
var textColorNomal:UIColor = UIColor.blackColor()
var textColorHighlight:UIColor = UIColor.redColor()
var isShown: Bool!
//MARK: Lifecycle
override func awakeFromNib() {
print("awakeFromNib")
super.awakeFromNib()
initSubviews()
configView()
}
override func layoutSubviews() {
super.layoutSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
func initSubviews() {
if let nibsView = NSBundle.mainBundle().loadNibNamed("DropdownMenuView", owner: self, options: nil) as? [UIView] {
let nibRoot = nibsView[0]
self.addSubview(nibRoot)
nibRoot.frame = self.bounds
}
}
required init(uSelection: Selection = Selection.Default, uIconType:IconType = IconType.Default, uMenuTitles:[String]) {
self.selection = uSelection
self.iconType = uIconType
self.menuTitles = uMenuTitles
super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
}
private func configView() {
switch (selection) {
case Selection.Multiple:
tableView.allowsMultipleSelection = true
default:
tableView.allowsMultipleSelection = false
}
tableView.registerNib(UINib(nibName: "DropdownMenuCell", bundle: nil), forCellReuseIdentifier: "DropdownMenuCell")
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
hideMenu()
}
internal func show() {
if self.isShown == false {
self.showMenu()
}
}
internal func hide() {
if self.isShown == true {
self.hideMenu()
}
}
func showMenu() {
self.isShown = true
if let app = UIApplication.sharedApplication().delegate as? AppDelegate, let window = app.window {
window.bringSubviewToFront(self)
}
// Animation
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.alpha = 1
})
}
func hideMenu() {
self.isShown = false
// Animation
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.alpha = 0
})
}
}
//MARK: UITableViewDelegate methods
extension DropdownMenuView: UITableViewDelegate {
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat(menuTitles.count) * cellHeight
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return cellHeight
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DropdownMenuCell") as! DropdownMenuCell
cell.lblTitle.text = menuTitles[indexPath.row]
cell.iconType = iconType
return cell
}
}
//MARK: UITableViewDataSource methods
extension DropdownMenuView: UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuTitles.count
}
}
I tried to remove outlets and connect again, but I wasn't lucky. It isn't working anymore. You can check my full demo project here:
https://www.dropbox.com/s/5udbl2kn9vnwjar/ModuleDemo.zip?dl=0
You click on "Label" on StartVC to call custom UIView.
I hope what I ask is possible. Any helps always are appropriate!
I am trying to initialize view controller from my UiView. But i am getting error on the line self.presentViewController(vc, animated: true, completion: nil) . I am trying to show another view controller after click on a table row. i have already initialized storyboard.
import UIKit
class CustomSwipeOut: UIView , UITableViewDataSource , UITableViewDelegate {
var label: UILabel = UILabel()
var myNames = ["item1","item2","item3"]
override init(frame: CGRect) {
super.init(frame: frame)
self.addCustomView()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addCustomView()
{
//add blank subview to the view
var blankView : UIView = UIView(frame: CGRectMake(0, 0, 300, 100))
blankView.backgroundColor = UIColor.greenColor()
self.addSubview(blankView)
//creating a tableview programmatically
var tblView : UITableView = UITableView()
tblView.frame = CGRectMake(0, 100, 300, 200)
self.addSubview(tblView)
tblView.delegate = self
tblView.dataSource = self
tblView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "myCell")
}
//pragma mark- table view data source methods
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("myCell") as UITableViewCell
cell.textLabel?.text = self.myNames[indexPath.row]
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.myNames.count
}
//pragma mark - table view delegate methods
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
switch indexPath.row {
case 0:
println("index o clicked")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("MoneySum") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
case 1:
println("index 1 clicked")
case 2:
println("index 2 clicked")
default:
println("no index")
}
}
}
presentViewController:animated:completion: is a method defined only for UIViewController, not UIView (see Apple doc here).
Your UIView is probably in the view hierarchy managed by a UIViewController.
A solution would be using a reference to that parent UIViewController and invoking presentViewController:animated:completion: on it.
However..i accomplised using a delegate to pass an id from UIView to UIViewController and checking to the id i instantiated ViewController From UIViewController class as Para said in his answer . I did it as below
Steps:
1) First create a protocol
2) create a Variable delegate conforming to protocol
3)Then create a call back method.
//Step1:
protocol SendIndexDelegate{
func sendIndex(Int);
}
class CustomSwipeView: UIView , UITableViewDataSource , UITableViewDelegate {
var delegate : SendIndexDelegate? //Step2
override init(frame: CGRect) {
super.init(frame: frame)
self.addCustomView()
}
......
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var row = indexPath.row
//for optional binding
if let temp = self.delegate {
delegate?.sendIndex(row) //Step 3
}else{
println("optional value contains nill value")
}
}
}
Steps Continued for Another Class:
4) Conform to the protocol SendIndexDelegate(so method sendIndex(Int) must be impelemented by this class)
5) Assign the value self in variable delegate in the optional variable delegate(it says that i will act as delegate for Class CustomSwipeView and implement the method sendIndex(Int))
6) Now implement the method and add body to it(because it has been delegate so must handle actions of the above class through call back method)
class RootViewController: UIViewController,SendIndexDelegate //Step4 {
let rect: CGRect = CGRect (x: self.view.frame.size.width, y :10 , width: self.view.frame.size.width-50, height: self.view.frame.size.height-10)
var a = CustomSwipeView(frame : rect)
a.delegate = self//step5
self.myView = a
self.view.addSubview(self.myView)
}
// Step 6:
func sendIndex(row : Int){
switch row {
case 0:
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let moneySummaryVC: MoneySummaryVC = storyboard.instantiateViewControllerWithIdentifier("moneyVC") as! MoneySummaryVC
self.navigationController?.pushViewController(moneySummaryVC, animated: true)
default:
println("no index")
}
}
You can use window to present any ViewController from your UIView Class. See this answer: https://stackoverflow.com/a/75396813/7385095
i have a UICollectionview that gets images form Parse.
I'm now trying to push to a detail view then I'm push on a image in the UICollectionView.
Do anybody have any idea on how to do this?
Here is my code:
viewcontroller:
import UIKit
import Parse
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
#IBOutlet var collectionView: UICollectionView?
var imageFilesArray:NSArray = NSArray()
var refreshControl: UIRefreshControl!
// var isAscending = true
override func viewDidLoad() {
super.viewDidLoad()
self.refreshControl = UIRefreshControl()
self.refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
self.refreshControl.addTarget(self, action: Selector("imageRefresh"), forControlEvents: UIControlEvents.ValueChanged)
self.refreshControl.tintColor = UIColor.whiteColor()
self.collectionView?.addSubview(refreshControl)
// Do any additional setup after loading the view, typically from a nib.
//let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
//layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 20, right: 10)
//layout.itemSize = CGSize(width: 150 , height: 150)
// collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView!.dataSource = self
collectionView!.delegate = self
collectionView!.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "imageCell")
collectionView?.alwaysBounceVertical = true
//collectionView!.backgroundColor = UIColor.whiteColor()
self.view.addSubview(collectionView!)
parseQuery()
}
func parseQuery() {
//query
var query = PFQuery(className: "photo")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
self.imageFilesArray = objects
//println(self.imageFilesArray)
}
self.collectionView?.reloadData()
}
}
func imageRefresh() {
parseQuery()
self.refreshControl.endRefreshing()
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
println(self.imageFilesArray.count)
return self.imageFilesArray.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("imageCell", forIndexPath: indexPath) as CollectionViewCell
cell.backgroundColor = UIColor.blackColor()
let imageObject = self.imageFilesArray.objectAtIndex(indexPath.row) as PFObject
let imageFile = imageObject.objectForKey("imageFile") as PFFile
imageFile.getDataInBackgroundWithBlock{
(data: NSData!, error: NSError!) -> Void in
if error == nil {
cell.imageView.image = UIImage(data: data)
}
}
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
collectionviewcell:
import UIKit
class CollectionViewCell: UICollectionViewCell {
#IBOutlet var imageView: UIImageView!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
imageView.contentMode = UIViewContentMode.ScaleToFill
contentView.addSubview(imageView)
}
}
Detailviewcontroller:
import UIKit
import Parse
class photoDetailViewController: UIViewController {
#IBOutlet var detailImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
i hope somebody can help on on how to write the code to push to the detail view, and show the same image that was pressed.
--
OlePetter
Update your didSelectItemAtIndexPath method,
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
var detailsViewController: DetailsViewController = DetailsViewController(nibName:"DetailsViewController",bundle:nil)
self.presentViewController(detailsViewController, animated: true) { () -> Void in
}
}
Note: In place of DetailsViewController write your own Details ViewController's name. and write you own nibName.