Dynamic UIPopoverController Size? - objective-c

I have a UIPopoverController in my app which simply displays two UILabels beside each other with a list of words in each of them. However sometimes there are only a couple of words in each list meaning there is tons of blank space in the popover view.
How can I make it so that the popover view in at least height dynamically adapts to how many lines of words there are in my label?
Any help always appreciated, thanks.

If text in label is specified before popover shows, you can achieve this by using similar code in viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
// ...
CGFloat height = [label.text sizeWithFont:label.font
forWidth:label.frame.size.width
lineBreakMode:label.lineBreakMode].height;
// This calculates only height of the label, you may want to add some margins, etc.
CGSize size = CGSizeMake(self.view.frame.size.width, height);
self.contentSizeForViewInPopover = size;
}

Related

Not editable NSTextfiled, to make it auto resize when string is too long, like english word to French

As my question being posted, in my textfield, when I open my app in English, it works well, but when switching to French, we know French word is quite long sometimes and in that case, words showing in the textfield will be cut off.
I tried some customised way for textfield on stack overflow, but it works well for editable textfield, when I made it none-editable, the behaviour will be wired.
It's like when the word is too long, it just make textfield longer, meaning just increase width, not height. What I'm expecting is keeping width fix while changing height when word is too long.
intrinsicSize = [super intrinsicContentSize];
NSTextView *textView = (NSTextView *)fieldEditor;
NSRect usedRect = [textView.textContainer.layoutManager usedRectForTextContainer:textView.textContainer];
kind of two main func I used, when it's editable, everything went well and height changes while width fix, but when it's none editable, only width changes.
Any advice?
In your NSTextField subclass override following methods. Also make sure that NSTextField is set to wrap in IB. Add constraints to it.
-(NSSize)intrinsicContentSize
{
// If wrap is not enabled return the original size
if ( ![self.cell wraps] ) {
return [super intrinsicContentSize];
NSRect frame = [self frame];
CGFloat width = frame.size.width;
// This will allow to grow it in height and not width
frame.size.height = CGFLOAT_MAX;
CGFloat height = [self.cell cellSizeForBounds: frame].height;
// return the calculated height
return NSMakeSize(width, height);
}
// Listen to text change notification and invalidate the default size
- (void)textDidChange:(NSNotification *)notification
{
[super textDidChange:notification];
[self invalidateIntrinsicContentSize];
}

UIVIew from XIB with Autolayout to UItableView Header

I am writing because I have a problem with the Auto Layout.
I'm trying to create a simple view in InterfaceBuilder with Auto Layout I want to load code and enter as a header of a table (not as header section). I explain briefly what are the characteristics.
The imageView must be square and must be as wide as the screen.
The space under the picture to the bottom of view that contains the button and label must be high 50 points.
Between image and button has to be a fixed distance of 12 points.
Between image and label must be a fixed distance of 13 points.
All these features are able to get them with Auto Layout. I added a constraint to the aspect ratio of the image (1: 1) and the various constraints for distances. all right.
The real problem is that by launching the app on iphone 6+ simulator (414 points of width), the image (with the label and button) goes above the cells.
Enabling various transparencies I noticed that the superView of Image View, only increase the width. It does not increase its height! How do I fix?
This is the code:
- (void)viewDidLoad{
//...
PhotoDetailsHeaderView *hView = (PhotoDetailsHeaderView *)[[[NSBundle mainBundle] loadNibNamed:#"PhotoDetailsHeaderView" owner:self options:nil] objectAtIndex:0];
hView.delegate = self;
self.tableView.tableHeaderView = hView;
//...
}
This is how I create the xib:
and this is how it is on the simulator, the green box is Uiimageview and the yellow box (under green box) is the mainview (or superview):
How can fix it?
Many thanks to all!
You'll need to add a property to store your PhotoDetailsHeaderView:
#property (nonatomic, strong) PhotoDetailsHeaderView *headerView;
Then calculate its expected frame in viewDidLayoutSubviews. If it needs updating, update its frame and re-set the tableHeaderView property. This last step will force the tableView to adapt to the header's updated frame.
- (void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
CGRect expectedFrame = CGRectMake(0.0,0.0,self.tableview.size.width,self.tableView.size.width + 50.0);
if (!CGRectEqualToRect(self.headerView.frame, expectedFrame)) {
self.headerView.frame = expectedFrame;
self.tableView.tableHeaderView = self.headerView;
}
}
The problem is probably that in iOS you have to reset the header of the table view manually (if it has changed its size). Try something along these lines:
CGRect newFrame = imageView.frame;
imageView.size.height = imageView.size.width;
imageView.frame = newFrame;
[self.tableView setTableHeaderView:imageView];
This code should be in -(void)viewDidLayoutSubviews method of your view controller.

MPVolumeView Dynamic Width

Im trying to do something very simple. Have a slider for volume that changes in width based on the devices' size or orientation.
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpVolumeView];
}
- (void) setUpVolumeView {
// Volume control
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:self.myBoxForVolume.bounds];
[self.myBoxForVolume addSubview:volumeView];
//[volumeView sizeToFit];
}
I set the myBoxForVolume a certain distance from the left bound of the device's view and a certain distance from the right bound of the device's view in my storyboard. I would like the volumeView to have the same exact width as the myBoxForVolume (keeping in mind that myBoxForVolume can change in size), but for some reason I am unable to establish volumeView with the correct bounds.
Missing one line of code that mades all of this happen.
volumeView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
Add a line like that to the setUpVolumeView method solves this issue of resizing.

Autolayout: how does fittingSize work exactly?

I have created a subclass of NSTextField that changes its height according to the text it contains. I now want to insert it in another view (an NSTableCellView) and make the view resize according to the height of the text field.
I want to use the -(NSSize)fittingSize method of NSView but unfortunately it doesn't seem to call the fittingSize method of its subviews nor their intrinsicContentSize method.
Here is the code I use for the NSTableCellView subclass:
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
self.expandingTextField = [[JSExpandingTextField alloc] init];
[self addSubview:self.expandingTextField];
[self removeConstraints:self.constraints];
NSDictionary *row = NSDictionaryOfVariableBindings(expandingTextField);
[self addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|-20-[expandingTextField]-28-|"
options:0 metrics:nil views:row]];
}
return self;
}
- (NSSize)fittingSize
{
return [super fittingSize];
}
I override the fittingSize method here only to put a breakpoint or an NSLog.
Here is the code of the table view delegate that provides the height of the table cell:
- (JSDynamicTableCellView *)dummyCell
{
if (!_dummyCell) {
_dummyCell = [[JSDynamicTableCellView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 100, 100)];
}
return _dummyCell;
}
- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
{
self.dummyCell.expandingTextField.stringValue = #"Test";
NSLog(#"Cell size %#",NSStringFromSize([self.dummyCell fittingSize]));
return [self.dummyCell fittingSize].height;
}
All of this always returns an height for dummyCell of 69 independent of the size of the expanding textfield in the cell.
The question is: how does the 'fittingSize' method figure out the size of its subviews? Should it call their 'fittingSize' or 'ntrinsicContentSize' methods or is it something else?
fittingSize is conceptually simple. It collects all of the constraints that have been added to your view or one of its subviews (recursively), and then it determines the size of the view based on only those constraints. You can think of it as determining the smallest size that is big enough to show the contents of that view hierarchy.
Edit:We need to be quite clear here. fittingSize returns minimum values and will return 0 for any dimension that is not fully specified. For example, if the vertical constraint tying a view to the bottom of its superview is omitted then the fitted height will be 0.
Edit: I just realized what you're probably running into: fittingSize is computing the text field as if it were just one long line, that does not wrap. You can confirm this by giving it a string value with one or more newlines: now the height should be bigger!
So how to fix this? Well, you have a text field, and you give it contents, and you want to know its height. But if the text field wraps, the height is going to depend on the width: make it narrower, and the text field will wrap to more lines, so it will consume more height. So in order to measure the preferred height for a wrapping text field, you have to tell it the width to wrap at.
On OS X Mountain Lion and iOS 6, you can do that with the [NSTextField setPreferredMaxLayoutWidth:] method. For example, if you want to compute the height based on a width of 100, you would call [textField setPreferredMaxLayoutWidth:100]; now fittingSize will report a height for the text field based on it wrapping at a width of 100.
By the way, this is a bad idea:
[self removeConstraints:self.constraints];
Because it removes constraints that other parts of the system have added. You should only ever remove a constraint that you created, either in code or in IB.
Try this (to do this click on the background of the xib or storyboard)

iOS - UITableViewCell's image go ontop of table upon selection?

I have 2 tables in one view. Table A lists a bunch of users. Table B lists a users objects. When a row is selected in Table A, Table B is reloaded with the objects that belong to that user.
So when a user selects a row in Table A, the image in the background of the cell changes to the highlighted version of the image.
Here is the normal version of the background image:
Here is the highlighted version of the background image:
As you can see, the highlighted version has a small arrow on the right of it. This arrow is beyond the width of the table cell the table itself. When the row is selected, the image changes as it should, but the image is sized down to fit the whole image into the cell.
What I would like to happen is the image goes outside of the table, or on top of the table for that selected row.
One possible solution I thought was to center the table on the selected row and then overlay that image, but if the user was to try to scroll through the table, the image would need to move and that would be a big pain.
So what I would like to know is it is possible to extend the cell's size beyond the table one it is selected?
Thanks in advance!
EDIT:
The following does not work, just in case anyone was going to try:
[cell setFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.size.width+20, cell.frame.size.height)];
Setting a views clipsToBounds property to NO will allow the view to draw outside of its own frame.
In your UITableViewController subclass:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do what you normally do here, if anything then add...
self.view.clipsToBounds = NO;
}
Doing this has a side effect where you will see full cells be created at the bottom or top of the tableview instead of them scrolling partially into view. Either put the table view into another view that has clipsToBounds set to YES, align the edges of the table view with the edges of the screen, or have views covering over the bottom and top (like a UIToolbar and UINavigationBar normally would).
To get the UITableViewCell's selectedBackgroundView to extend past the table view's frame create a subclass of UITableViewCell and override the layoutSubviews method.
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"YQGyZ"]];
self.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"CQXYh"]];
self.textLabel.backgroundColor = [UIColor clearColor];
self.detailTextLabel.backgroundColor = [UIColor clearColor];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect frame = self.selectedBackgroundView.frame;
frame.size.width += 13; // where 13 is the size of the arrow overhang from the same images
self.selectedBackgroundView.frame = frame;
// You can also change the location of the default labels (set their background colors to clear to see the background under them)
self.textLabel.frame = CGRectMake(70, 0, 148, 30);
self.detailTextLabel.frame = CGRectMake(70, 30, 148, 30);
}
Good luck.
I would recommend modifying the image resource of the unselected cell background such that it is the same width as the selected background, but just has a transparent rectangle on the side.