Self sizing UICollectionViewCell in iOS14 - uicollectionviewcell

Stack: Mac OS 10.15.6, Xcode Version 12.0 (12A7209)
I have a self sizing collection cell. I override preferredLayoutAttributesFitting to get the self sizing feature. Everything works great PRIOR to iOS 14 ("1"). However, in iOS 14 (when targeting the simulator or actual device), this cell seems to be "broken" that is, it's now shown ("2"). Furthermore, the layout engine complained about the layout constraints ("3").
Have you seen a similar issue?

I had the same problem, the cell was looking good on iOS 11, 12, 13, but on iOS 14 simulator somehow the preferredLayoutAttributesFitting returned with the same height for every cell, ignoring that some cell needs more height.
The problematic code on iOS 14 (working on iOS 13 and below):
override func preferredLayoutAttributesFitting(
_ layoutAttributes: UICollectionViewLayoutAttributes
) -> UICollectionViewLayoutAttributes {
layoutAttributes.bounds.size.height = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}
However there is a contentView property that you can pass to this function (if your cell is subclass of UICollectionViewCell you already have that)
Solution (working on all iOS version I've tried):
override func preferredLayoutAttributesFitting(
_ layoutAttributes: UICollectionViewLayoutAttributes
) -> UICollectionViewLayoutAttributes {
layoutAttributes.bounds.size.height = contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}
and voila it works again.
I would appreciate if someone could explain what is happening here in the background, what has changed in iOS 14...
I'm not saying this is the solution for all iOS 14 self-sizing cell issue but it's worth a try! :)

Unfortunately the other answer didn't work for me, but I found another solution:
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)
layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
return layoutAttributes
}
I got the solution from here

Related

Setting eraser type to bitmap for PencilKit (iOS)

Using PencilKit for iOS, how do I set the eraser tool to .bitmap for PKToolPicker?
I can't find any setting for PKToolPicker. Trying to use PKCanvasView to observe and set the tool's eraserType as .bitmap also does not work.
override func toolPickerSelectedToolDidChange(_ toolPicker: PKToolPicker) {
var tool = toolPicker.selectedTool as? PKEraserTool
if tool != nil {
tool?.eraserType = .bitmap
}
}
The PKEraser is a struct, so when you change its eraserType, you're actually modifying a copy of the tool that's being used in the canvas.
What you need to do is simply set the PKCanvasView tool property and it will work.
override func toolPickerSelectedToolDidChange(_ toolPicker: PKToolPicker) {
var tool = toolPicker.selectedTool as? PKEraserTool
if tool != nil {
tool?.eraserType = .bitmap
}
// this line below will do the trick
canvasView.tool = tool
}
Let me know if it worked! 😊
Applies to iOS 13 and iOS 14
To set the toolpicker's selected tool as a bitmap eraser (where toolPicker is the PKToolPicker):
toolPicker?.selectedTool = PKEraserTool(.bitmap)
To set the canvas view's tool to a bitmap eraser (where canvasView is the PKCanvasView):
canvasView.tool = PKEraserTool(.bitmap)
This code, based on your example, will keep the toolpicker's erase tool as bitmap(pixel eraser) even if vector(object eraser) was chosen. (tested on iOS 14)
func toolPickerSelectedToolDidChange(_ toolPicker: PKToolPicker) {
if toolPicker.selectedTool is PKEraserTool {
toolPicker.selectedTool = PKEraserTool(.bitmap)
}
}

my program seems good on Windows,while on Ubuntu it is crashed

I'm programing a plane game on Windows by QT which seems good,while on Ubuntu it is crashed.It has a QLinkedList<Bullet *> Bullet_list.and it is crashed after Bullet_list.removeOne(*ite)
I've tried judging every Null-pointer,adding delete *ite after removeOne(),but it doesn't work.
Plane_Player *Plane_p;
connect(timer,SIGNAL(timeout()),this,SLOT(Refresh()));
void GameWindow::Refresh(){
QLinkedList<Bullet*>::iterator ite;
for(ite = Plane_p->Bullet_list.begin();ite != Plane_p->Bullet_list.end();++ite)
{
(*ite)->Go();//move the bullets on the screen
if((*ite)->isOutOfBound())
Plane_p->Bullet_list.removeOne(*ite);//crashed after this.
}
}
class Plane_Player
{
public:
QLinkedList<Bullet *> Bullet_list;
}
in the function Refresh(),there is other removeOne(),and it's all crashed after it.
I hope it won't be crashed on Ubuntu.
the whole project:https://github.com/Vinolzy/QT
Qt documentation states that:
If you want to insert, modify, or remove items in the middle of the
list, you must use an iterator.
So far so good. But I think the problem is that you reuse the iterator after removing an element from your linked list. To fix it you need to update your iterator after removal. For example, you can rewrite your loop like:
QLinkedList<Bullet*>::iterator ite = Plane_p->Bullet_list.begin();
while (ite != Plane_p->Bullet_list.end())
{
(*ite)->Go();
if ((*ite)->isOutOfBound())
{
ite = Plane_p->Bullet_list.erase(ite);
}
else
{
++ite;
}
}
And finally, it works differently on different platforms because your code leads to an undefined behavior.

NSAttributedString drawRect doesn't draw images on-screen on Mojave

I have a working app that draws NSAttributedStrings into a custom view. The NSAttributedStrings can included embedded images. This works on versions of macOS prior to Mojave. The app can display the strings on screen, print them, and save them to image files.
This is apparently broken under Mojave. Weirdly, printing and saving to image files still works; but on-screen, the strings display only the text and not the embedded images. Proper space is left for the images, but that space is blank.
I've tested by building a small app that shows a window with an NSTextField (a label) and a custom view. It makes a single NSAttributedString with an embedded image. It applies that string to the attributedStringValue of the label, and also calls drawInRect: on the same string in the drawRect: method of the custom view. In the label, the string is displayed correctly, image and all. But in the custom view, only the text appears, and the space where the image should be is blank.
Anybody got a clue why this is happening on Mojave but not on earlier versions of macOS?
Here is the code that makes the string (and caches it, for re-use):
static NSMutableAttributedString* sgAttrString = nil;
/*
* Creates an attributed string the first time it's called,
* then returns that same string each time it's called.
*/
+ (NSAttributedString*)getAttributedString
{
if (sgAttrString == nil)
{
NSFont* font = [NSFont fontWithName:#"Helvetica" size:24.0];
NSDictionary *attrs = #{
NSFontAttributeName: font
};
sgAttrString = [[NSMutableAttributedString alloc] initWithString:#"Daisy: " attributes:attrs];
NSImage* daisy = [NSImage imageNamed:#"daisy.png"];
[daisy setSize:NSMakeSize(24,24)];
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
// I'm aware that attachment.image is available only on macOS 10.11 and later.
// It's not an issue in my real project.
attachment.image = daisy;
NSMutableAttributedString* imageStr = [[NSMutableAttributedString alloc] init];
[imageStr setAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]];
[sgAttrString appendAttributedString:imageStr];
[sgAttrString appendAttributedString: [[NSAttributedString alloc] initWithString:#" !!" attributes:attrs]];
}
return sgAttrString;
}
Here is the code that applies the string to the NSTextField:
NSAttributedString* str = [Utilities getAttributedString];
self.label.attributedStringValue = str;
And here is the code that draws the string in a custom NSView:
NSAttributedString* str = [Utilities getAttributedString];
[str drawInRect:NSMakeRect(50,50, 300, 40)];
Again, this behavior seems to occur only in Mojave! Thanks in advance for any help.

Awesome WM - Application's fullscreen mode without taking whole screen

i'm looking for a way to let applications using their own fullscreen mode but without resizing their own windows.
For example, i want to watch a video on a web browser in fullscreen mode to hide all other bars/content of the browser/website except the video but i want to keep my display layout to see other apps at the same time.
Any ideas?
Thanks !
I did not test the following, but it might work. The idea of the rule is that it is used to detect which windows should not be fullscreend. It is a normal awful.rules-rule. All clients which do not match the rule are handled normally by awful.ewmh.geometry.
local rule = { class = "Firefox" }
client.disconnect_signal("request::geometry", awful.ewmh.geometry)
client.connect_signal("request::geometry", function(c, context, ...)
if context ~= "fullscreen" or not awful.rules.match(c, rule) then
awful.ewmh.geometry(c, context, ...)
end
end)
Edit: To toggle this behaviour I suggest the following:
local no_fullscreen = true
local rule = { class = "Firefox" }
client.disconnect_signal("request::geometry", awful.ewmh.geometry)
client.connect_signal("request::geometry", function(c, context, ...)
if not no_fullscreen or context ~= "fullscreen" or not awful.rules.match(c, rule) then
awful.ewmh.geometry(c, context, ...)
end
end)
Then add a key binding with callback function function() no_fullscreen = not no_fullscreen end.

UICollectionView with autosizing cells incorrectly positions supplementary view

I am using a UICollectionView with a Flow Layout and trying to get the collectionView to size the cells appropriately according to AutoLayout constraints.
While the cells work as intended, I am running in to issues with the layout of any supplementary views that I add to the CollectionView.
Specifically, the supplementaryView will be in the wrong position (i.e., the y origin is incorrect) on initial layout, before 'correcting' itself after I scroll.
For reference, here is how I am configuring my cell sizing:
1. Set the collectionViewLayout's estimated item size
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.estimatedItemSize = CGSizeMake(375, 50.0)
layout.minimumInteritemSpacing = 0.0
layout.minimumLineSpacing = 0.0
let view = UICollectionView(frame: CGRectZero, collectionViewLayout: layout)
view.backgroundColor = UIColor.whiteColor()
view.alwaysBounceVertical = true
return view
}()
2. Use subclasses of AutoLayoutCollectionViewCell
class AutoLayoutCollectionViewCell: UICollectionViewCell {
override func preferredLayoutAttributesFittingAttributes(layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
layoutIfNeeded()
layoutAttributes.bounds.size.height = systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
return layoutAttributes
}
}
Note that at this point, everything works as intended.
The next step is where we fail.
3. Provide a reference size for a header
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSizeMake(CGRectGetWidth(collectionView.frame), 30.0)
}
My question is: Why does this happen? How can I get this to correct? How am I supposed to handle supplementary views within a collectionView that self-sizes its cells??
I had the same problem, what solved it for me was to subclass UICollectionViewFlowLayout and override the following function:
override func invalidationContext(forPreferredLayoutAttributes preferredAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutInvalidationContext {
let context = super.invalidationContext(forPreferredLayoutAttributes: preferredAttributes, withOriginalAttributes: originalAttributes)
context.invalidateSupplementaryElements(ofKind: UICollectionElementKindSectionHeader,
at: [originalAttributes.indexPath])
return context
}

Resources