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!
Related
I face into weird animation behaviour when I try to implement UIContentConfiguration for my UITableView.
I've implemented simple downscale animation on touch for my cell, but it doesn't work as expected. UILabel upscale first, and after that downscale.
I realized that animation behaviour related with updating configuration when touch began.
I've found that app has to call setNeedsUpdateConfiguration in animation block, but all my attempts have failed.
Code samples below:
ViewController.swift
class ViewController: UIViewController {
var array: [String] = ["Test 1", "Test 2", "Test 3"]
private lazy var tableView: UITableView = {
let table = UITableView()
table.register(MyCustomTableViewCell.self, forCellReuseIdentifier: "MyCustomTableViewCell")
table.dataSource = self
table.delegate = self
return table
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "MyCustomTableViewCell", for: indexPath) as? MyCustomTableViewCell {
cell.configure(configuration: AnimatableContentViewConfiguration(text: array[indexPath.row]))
return cell
}
return UITableViewCell()
}
}
MyCustomCell.swift
class MyCustomTableViewCell: UITableViewCell {
func configure(configuration: AnimatableContentViewConfiguration) {
contentConfiguration = configuration
}
}
AnimatableContentViewConfiguration.swift
struct AnimatableContentViewConfiguration: UIContentConfiguration {
fileprivate var titleText: String = ""
init(text: String) {
titleText = text
}
func makeContentView() -> UIView & UIContentView {
AnimatableContentView(configuration: self)
}
func updated(for state: UIConfigurationState) -> AnimatableContentViewConfiguration {
self
}
}
AnimatableContentView.swift
final class AnimatableContentView: UIView, UIContentView {
private lazy var titleLabel: UILabel = {
UILabel(frame: .init(x: 5, y: 5, width: 100, height: 20))
}()
var configuration: UIContentConfiguration {
didSet {
if let configuration = configuration as? AnimatableContentViewConfiguration {
configure(configuration)
}
}
}
required init(configuration: UIContentConfiguration) {
self.configuration = configuration
super.init(frame: .zero)
addSubview(titleLabel)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure(_ configuration: AnimatableContentViewConfiguration) {
titleLabel.text = configuration.titleText
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
highlight(true)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
highlight(false)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
highlight(false)
}
func highlight(_ touched: Bool) {
highlight(touched, completion: nil)
}
func highlight(_ touched: Bool, completion: ((Bool) -> Void)?) {
let scaleSize = 0.97
let transform = CGAffineTransform(scaleX: scaleSize, y: scaleSize)
UIView.animate(withDuration: 0.4,
delay: 0,
usingSpringWithDamping: 0.8,
initialSpringVelocity: 0.8,
options: [.allowUserInteraction, .curveEaseIn],
animations: {
self.transform = touched ? transform : .identity
}, completion: completion)
}
}
I'll appreciate for any help with my issue.
I have a dynamic collectionView in TableView and there are three errors:
the cells are not displayed correctly when the application starts
when I do inserItem the cells flicker as if they are rebooting
and most importantly when collectionView.insertItems the first four cells are hidden, the video
thanks
MainViewController
class ViewController: UIViewController, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setting()
}
func setting(){
getData()
tableView.dataSource = self
tableView.delegate = self
tableView.estimatedRowHeight = UITableView.automaticDimension
tableView.rowHeight = UITableView.automaticDimension
}
//load data
func pagination(_ completion: (()->())?){
SmartNetworkSevrice.getGoods(with: url) { [unowned self] (data) in
guard data.modals.count > 0 else {
self.tableView.tableFooterView = nil
return
}
self.goods.append(contentsOf: data.modals)
self.offSet += data.modals.count
DispatchQueue.main.async {
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.tableFooterView = nil
if self.goods.count == data.modals.count || self.isRefresh {
self.tableView.reloadRows(at: [indexPath], with: .none)
} else {
if let cell = self.tableView.cellForRow(at: indexPath) as? TVCellGoods {
UIView.performWithoutAnimation {
self.tableView.beginUpdates()
cell.insertGoods(data.modals)
cell.layoutIfNeeded()
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height
self.tableView.endUpdates()
}
}
}
completion?()
}
}
// define bottom of tableView
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard scrollView == self.tableView else { return }
if (!isMoreDataLoading) {
// Вычислить позицию длины экрана до нижней части результатов
let scrollViewContentHeight = scrollView.contentSize.height
let scrollOffsetThreshold = scrollViewContentHeight - scrollView.bounds.size.height
if(scrollView.contentOffset.y > scrollOffsetThreshold && scrollView.isDragging) {
isMoreDataLoading = true
self.tableView.isScrollEnabled = false;
self.tableView.isScrollEnabled = true;
pagination(nil)
}
}
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "goods", for: indexPath) as? TVCellGoods else { return UITableViewCell() }
guard bestGoods.count != 0, goods.count != 0 else { return UITableViewCell() }
cell.delegate = self
cell.configure(bestGoods, goods, categories)
// автообновление высоты
self.tableView.beginUpdates()
cell.collectionViewHeight.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height
self.tableView.endUpdates()
return cell
}
}
extension ViewController: UITableViewDelegate, CallDelegate {
func callMethod() {}
func callMethod(push vc:UIViewController) {
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
TableViewCell with collectionView
class TVCellGoods: UITableViewCell {
#IBOutlet weak var collectionView:UICollectionView!
#IBOutlet weak var collectionViewHeight:NSLayoutConstraint!
weak var delegate:CallDelegate?
var bestGoods = [Goods]() // лучшие товары
var goods = [Goods]() // все товары
var categories = [Menu]()
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.tag = 2
collectionView.isScrollEnabled = false
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func configure(_ best:[Goods],_ goods:[Goods], _ category:[Menu]) {
self.bestGoods = best
self.goods = goods
self.categories = category
self.collectionView.reloadData()
}
func insertGoods(_ data:[Goods]) {
self.goods.append(contentsOf: data)
let count = self.bestGoods.count + self.categories.count + self.goods.count
let indexPaths = ((count - data.count) ..< count)
.map { IndexPath(row: $0, section: 0) }
self.collectionView.performBatchUpdates({
self.collectionView.insertItems(at: indexPaths)
}, completion: nil)
}
}
and CollectionViewCell
class CVCellGoods: UICollectionViewCell {
#IBOutlet weak var bgView: UIView!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var title: UILabel!
#IBOutlet weak var price: UILabel!
#IBOutlet weak var delivery: UIImageView!
#IBOutlet weak var premium: UIImageView!
override func prepareForReuse() {
super.prepareForReuse()
delivery.image = nil
premium.image = nil
title.text = nil
price.text = nil
imageView.image = nil
imageView.sd_cancelCurrentImageLoad()
}
override func awakeFromNib() {
super.awakeFromNib()
imageView.backgroundColor = UIColor(red: 215/255, green: 215/255, blue: 215/255, alpha: 1)
self.contentView.layer.cornerRadius = 5
self.contentView.layer.masksToBounds = true
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 0.5)
self.layer.shadowRadius = 1
self.layer.shadowOpacity = 0.3
self.layer.masksToBounds = false
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
}
}
EDIT: this gives a small bug at startup
TVCellGoods.swift
override func layoutSubviews() {
super.layoutSubviews()
self.collectionView.collectionViewLayout.invalidateLayout()
}
I just figured out how to solve your problem.
You gonna have to invalidate your collection view layout, as you are using an collectionView inside a tableView just add the following method on TVCellGoods.swift
override func layoutSubviews() {
super.layoutSubviews()
self.collectionView.collectionViewLayout.invalidateLayout()
}
I tested it, and worked!!
see video
It's not a good idea to add a scroll view inside another scroll view!
Do you have an example project in order to help you?
the cells are not displayed correctly when the application starts
You calculate collectionView itemSize in ViewDidLoad,
but in ViewDidLoad TableView & TableviewCell width not equal ViewController.
override func viewDidLoad() {
super.viewDidLoad()
print(view.frame.size.width) //320
print(tableView.frame.size.width) //414
}
You can try reloadData in ViewDidAppear.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print(view.frame.size.width) //320
print(tableView.frame.size.width) //320
tableView.reloadData()
}
when collectionView.insertItems the first four cells are hidden
Subclass UICollectionViewFlowLayout
class MyCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
TVCellGoods.swift
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.tag = 2
collectionView.isScrollEnabled = false
collectionView.collectionViewLayout = MyCollectionViewFlowLayout()
}
I am new in Swift and my english is not very well
The question is i build a dropdown view from this tutorial
youtube: https://youtu.be/22zu-OTS-3M
github: https://github.com/Archetapp/Drop-Down-Menu
He programmatically create a fantastic dropdown view without storyboard
the code run very good on my Xcode
but when I went to check the title with the button
I never get it.
this my code
class ViewController: UIViewController, GMSMapViewDelegate
override func viewDidLoad()
super.viewDidLoad()
let typeBTN = dropDownBtn()
self.view.addSubview(typeBTN)
typeBTN.setTitle("animal", for: .normal)
typeBTN.dropView.dropDownOptions = ["dog", "cat", "cow", "boy"]
// ....
protocol dropDownProtocol {
func dropDownPressed(string: String)
}
class dropDownBtn: UIButton, dropDownProtocol {
func dropDownPressed(string: String) {
self.setTitle(string, for: .normal)
self.dismissDropDown()
}
var dropView = dropDownView()
var height = NSLayoutConstraint()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.darkGray
dropView = dropDownView.init(frame: CGRect.init(x: 0, y: 0, width: 0, height: 0))
dropView.delegate = self
dropView.translatesAutoresizingMaskIntoConstraints = false
}
override func didMoveToSuperview() {
self.superview?.addSubview(dropView)
self.superview?.bringSubviewToFront(dropView)
dropView.topAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
dropView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
dropView.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
height = dropView.heightAnchor.constraint(equalToConstant: 0)
}
var isOpen = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if isOpen == false {
isOpen = true
NSLayoutConstraint.deactivate([self.height])
if self.dropView.tableView.contentSize.height > 150 {
self.height.constant = 170
} else {
self.height.constant = self.dropView.tableView.contentSize.height
}
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
self.dropView.layoutIfNeeded()
self.dropView.center.y += self.dropView.frame.height / 2
}, completion: nil)
}else{ dismissDropDown() }
}
func dismissDropDown() {
isOpen = false
NSLayoutConstraint.deactivate([self.height])
self.height.constant = 0
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
self.dropView.center.y -= self.dropView.frame.height / 2
self.dropView.layoutIfNeeded()
}, completion: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class dropDownView: UIView, UITableViewDelegate, UITableViewDataSource {
var dropDownOptions = [String]()
var tableView = UITableView()
var delegate: dropDownProtocol!
override init(frame: CGRect) {
super.init(frame: frame)
tableView.backgroundColor = UIColor.darkGray
tableView.delegate = self
tableView.dataSource = self
self.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dropDownOptions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = dropDownOptions[indexPath.row]
cell.backgroundColor = UIColor.darkGray
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.delegate.dropDownPressed(string: dropDownOptions[indexPath.row])
print(dropDownOptions[indexPath.row])
I have tried a lot to check when button title change. like this
print(typeBTN.currentTitle!)
print(typeBTN.titleLabel?.text! )
print(typeBTN.title(for: .normal))
//I get nothing when i pressed dropdown menu options?
because I want to do this
if typeBTN.currentTitle == "dog" {
//show some date at my mapview
}
but when I click the "dog" of dropdown menu
it never work
can somebody help me?
You can use the Delegation pattern to notify the title changes to your view controller.
Add the protocol:
protocol DropDownButtonDelegate: AnyObject {
func titleDidChange(_ newTitle: String)
}
Add in your DropDownButton class a delegate property:
weak var delegate: DropDownButtonDelegate?
Then in your dropDownPressed function:
func dropDownPressed(string: String) {
self.setTitle(string, for: .normal)
self.dismissDropDown()
delegate?.titleDidChange(string)
}
And finally in your view controller implement the DropDownButtonDelegate:
class ViewController: UIViewController, GMSMapViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let typeBTN = dropDownBtn()
self.view.addSubview(typeBTN)
typeBTN.delegate = self
typeBTN.setTitle("animal", for: .normal)
typeBTN.dropView.dropDownOptions = ["dog", "cat", "cow", "boy"]
}
}
extension ViewController: DropDownButtonDelegate {
func titleDidChange(_ newTitle: String) {
print(newTitle)
}
}
How do I handle a custom UIView button action inside a TableViewCell?
I have custom UIView with XIB which I added to TableView which is implementet in UIViewControler. For each cell I add my custom UIView in tableView function - cellForRowAt. Everything looks fine but I can't handle button action from added custom UIView for that cell. Can someone help me how to do that?
Edit:
My custom UIView which has own XIB.
protocol TicketButtonDelegate {
func starButtonAction(_: UIButton)
}
class TicketView: UIView {
#IBOutlet var ticketContentView : UIView!
var delegate: TicketButtonDelegate!
#IBOutlet weak var starButton : UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func commonInit() {
Bundle.main.loadNibNamed("TicketView", owner: self, options: nil)
addSubview(ticketContentView)
starButton.addTarget(self, action: #selector(starButtonAction(_:)), for: .touchUpInside)
ticketContentView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 132)
}
#objc func starButtonAction(_ sender: UIButton) {
delegate.starButtonAction(sender)
}
}
My UIViewController.
class MhdDashboardBottom: UIViewController, TicketButtonDelegate {
#IBOutlet weak var mhdTicketsTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
mhdTicketsTable.delegate = self
mhdTicketsTable.dataSource = self
mhdTicketsTable.register(UINib(nibName: "MhdTicketTableCell", bundle: nil), forCellReuseIdentifier: "MhdTicketCell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "MhdTicketCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? MhdTicketTableCell else {
fatalError("The dequeued cell is not an instance of MhdTicketTableCell")
}
let ticket = tickets[indexPath.row]
let ticketCell = TicketView()
ticketCell.delegate = self
ticketCell.tag = 700
var viewExists = false
for view in cell.contentCellView.subviews {
if view.tag == ticketCell.tag {
viewExists = true
break
}
}
if viewExists == false {
cell.contentCellView.addSubview(ticketCell)
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 132
}
func starButtonAction(_: UIButton) {
print("Works?")
}
}
My MhdTicketTableCell (UITableViewCell)
class MhdTicketTableCell: UITableViewCell {
#IBOutlet weak var contentCellView: UIView!
}
Rather than a protocol use a callback closure, it avoids view hierarchy math, tags and protocol declaration:
In the view delete the protocol
protocol TicketButtonDelegate {
func starButtonAction(_: UIButton)
}
Replace var delegate: TicketButtonDelegate! with weak var callback: (() -> Void)?
Replace
#objc func starButtonAction(_ sender: UIButton) {
delegate.starButtonAction(sender)
}
with
#objc func starButtonAction(_ sender: UIButton) {
callback?()
}
In the controller delete
func starButtonAction(_: UIButton) {
print("Works?")
}
Replace
ticketCell.delegate = self
with
ticketCell.callback = {
print("Works?", indexPath)
}
The index path and even the ticket are captured.
Well after very long research for answer I come up with solution.
Into my TicketView I had to add this function to pass touch events into subviews.
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
for subview in subviews {
if !subview.isHidden && subview.isUserInteractionEnabled && subview.point(inside: convert(point, to: subview), with: event) {
return true
}
}
return false
}
After this, I deleted delegate implementation and I just added
ticketCell.starButton.addTarget(self, action: #selector(starButtonAction(_:)), for: .touchUpInside)
into UIViewControlers cellForRow function and then added objc function
#objc func starButtonAction(_ sender: UIButton) {
print("Works?")
}
All thanks to this answered question.
I have a chartView and a customized tableViewcell.
And I try to use chartView add on my tableviewcell.
This ViewController is child ViewController.
I push to this ViewController, and I want to call tapIndexAction(index: 0) to hightlight my bar of index 0.
I also use "tableview didEndDisplaying" can't fill color.
What's wrong with me?
Thanks.
class ChartView: UIView {
let publishSub = PublishSubject<Int?>()
var isAlreadyInit = false
var chartInfo:ChartInfo?
init(info:ChartInfo?, frame:CGRect = CGRect.zero) {
self.chartInfo = info
super.init(frame:frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
if !self.isAlreadyInit {
if self.frame.width > 0 {
self.isAlreadyInit = true
self.drawChart()
}
}
}
func drawChart() {
if let tmpCharInfo = self.chartInfo {
let chartLayer = tmpChartInfo.getChartDrawLayer()
chartLayer.frame = self.bounds
chartLayer.drawChart()
self.layer.addSublayer(chartLayer)
}
}
func tapIndexAction(index: Int) {
if let chartLayer = (self.layer.sublayers?.last) as? ChartLayer {
chartLayer.tapIndex(index: index)
self.publishSub.onNext(index)
}
}
class ChartLayer: CALayer {
var drawInfo:ChartInfo
var touchFrame:[CGRect] = [CGRect]()
var drawLayers:[CAShapeLayer] = [CAShapeLayer]()
var tapIndex:Int?
init(info:ChartDrawInfo) {
self.drawInfo = info
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func tapIndex(index:Int) {
self.tapIndex = index
for idx in 0..<self.touchFrame.count {
let shapeLayer = self.drawLayers[idx]
if idx == index {
shapeLayer.fillColor = UIColor.red.cgColor //Not work in "tableview didEndDisplaying"
}else {
shapeLayer.fillColor = UIColor.blue.cgColor
}
}
}
}
class BarChartTableViewCell: UITableViewCell {
var barChartView: ChartView?
var chartInfo:ChartInfo?
func initCell(drawInfo: ChartInfo?) {
self.chartInfo = drawInfo
if self.barChartView != nil {
for view in self.contentView.subviews {
view.snp.removeConstraints()
view.removeFromSuperview()
}
}
self.barChartView = ChartView(drawInfo: self.chartInfo)
self.contentView.addSubview(barChartView)
barChartView?.snp.makeConstraints({ (make) in
make.left.equalTo(13)
make.top.equalTo(updateTimeLabel.snp.bottom)
make.right.equalToSuperview()
make.height.equalTo(202)
})
}
}
class ViewController: UITableViewDelegate, UITableViewDataSource {
let tableview = UITableView()
tableview.datasource = self
tableview.delegate = self
//numberOfRowInSection return 1
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
if let chartCell = cell as? BarChartTableViewCell {
chartCell.barChartView?.tapIndexAction(index: 0)
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let barChartCell = tableView.dequeueReusableCell(withIdentifier: "BarChartTableViewCell", for: indexPath) as! BarChartTableViewCell
barChartCell.initCell(drawInfo: chartInfo)
return barChartCell
}
}