Reputation: 4570
I have a Today Widget which displaying the upcoming train departures based on a pair of stations chosen in the main application. Given that the departure times changes with time, I have an API call in viewWillAppear
fetching the new times and repopulating the cells of a tableView.
Currently, the widget starts off with a height of what looks like 150-200 points in height. My updating logic attempts to set the preferredContent
height but this doesn't work. I have the tableView constrained to the top/bottom layout guides. I have tried resetting the tableView's frame height to the main view after telling it a new preferredContent.
Presumably, the callback of my network happens after viewWillAppear, so I invoke layoutIfNeeded
to trigger viewDidLayoutSubviews
where I reload the tableview.
None of this gets me what I want to see. A tableview populated by the departure times which is N times the height of a cell
where N is the number of departure times most recently fetched by my API call.
What am I missing? Any help would be greatly appreciated.
This is the relevant code where I attempt to re-height the extension.
override func viewWillAppear(_ animated: Bool) {
dao.fetchTrips { (trips) in
self.tripsDataSource.dataStore = trips
let numTrips = trips?.count
let rowHeight = 44 // static
let h = numTrips! * rowHeight
self.preferredContentSize = CGSize(width: 0, height: h)
self.view.layoutIfNeeded()
}
}
override func viewDidLayoutSubviews() {
self.tableView.reloadData()
}
I have noticed viewDidLayoutSubviews
is not called after layoutIfNeeded
is invoked in the completion handler. Although that may not be the issue, as the app-extension main view does not change after setting a new preferredContentSize
.
Upvotes: 0
Views: 766
Reputation: 253
I had the same problem. Few minutes ago I solved it. The default view of widget doesn't show the max height. You need to press show more , next to App title.
Remove your code and just add this to your widget class and on else branch set the height what you want. This will call when you hit show less/ show more.
@available(iOSApplicationExtension 10.0, *)
func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize){
if (activeDisplayMode == NCWidgetDisplayMode.compact) {
self.preferredContentSize = CGSize(width: 0, height: maxSize.height);
}
else {
self.preferredContentSize = CGSize(width: 0, height: self.tableView.contentSize.height);
}
}
Edited: My code:
import UIKit
import NotificationCenter
let groupappname = "group.***.***"
class MyCollectionViewController: UICollectionViewController , NCWidgetProviding,UICollectionViewDelegateFlowLayout {
var isEmptyData = true
var array = NSMutableArray()
var defaults = UserDefaults.init(suiteName: groupappname)!
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOSApplicationExtension 10.0, *) {
self.extensionContext?.widgetLargestAvailableDisplayMode = NCWidgetDisplayMode.expanded
} else {
// Fallback on earlier versions
}
registerObserver()
refreshData()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
removeObserver()
}
func refreshData(){
self.preferredContentSize = (self.collectionView?.contentSize)!
#somecode
self.collectionView?.reloadData()
}
func refreshData_NoData(){
self.preferredContentSize = (self.collectionView?.contentSize)!
self.collectionView?.reloadData()
}
func widgetPerformUpdate(completionHandler: @escaping (NCUpdateResult) -> Void) {
print("widgetperformupdate")
completionHandler(NCUpdateResult.newData)
}
@available(iOSApplicationExtension 10.0, *)
func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize){
if (activeDisplayMode == NCWidgetDisplayMode.compact) {
self.preferredContentSize = CGSize(width: 0, height: maxSize.height)
}
else {
self.preferredContentSize = CGSize(width: 0, height: (self.collectionView?.contentSize.height)!)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return array.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
#somecode
self.preferredContentSize = collectionView.contentSize
return cell
}
}
Upvotes: 1