UITableViewCell Transform Breaks in iOS 11 - ios

In an app I've built, I had a table view showing an image to the left of each cell by running the following code inside of cellForRowAtIndexPath:
cell.imageView.image = [UIImage imageNamed:myImage];
But the image was too big, so I shrunk it:
cell.imageView.transform = CGAffineTransformMakeScale(0.3, 0.3);
This worked just fine in iOS 10. But once I upgraded to the newest Xcode with the iOS 11 SDK, the images got enormous. It turns out that that second line of code transforming the image view is now doing nothing: I can comment it out, change the 0.3's to something else, etc., and it doesn't make any difference. CGAffineTransformMakeScale still has documentation in the new Xcode, so I'm assuming it wasn't deprecated, but then why did this break with iOS 11, and how do I fix it? Any ideas? Thanks in advance! Please note, I'm using Objective-C.
Edit:
Just tried 3 changes to the code:
Change the second line to cell.imageView.transform = CGAffineTransformMakeScale(0.0000001, 0.0000001);. Nothing happens (i.e., the image views and the images inside them are still just as huge).
Change the second line to cell.imageView.transform = CGAffineTransformMakeScale(0, 0);. The image disappears from the image view, but the image view is still the same size, and you can tell because it still displaces the text in the cell and pushes it far to the right.
Remove the first line of code (no longer assigning an image to the imageview). The imageview disappears, and the text moves all the way to the left of the cell.
Perhaps this can help shed some light on what's going on?

So if you are trying to adjust the image size to fit the imageView you should actually use the imageView's contentMode property like so:
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
or in Swift for others
cell.imageView.contentMode = .scaleAspectFit
This keeps the dimensions of the image and fits the maximum size image onto the imageView without changing the dimensions
You could also try UIViewContentModeScaleAspectFit (or .scaleAspectFill in Swift) which basically fills the dimensions of the imageView entirely, but if the picture is wider or taller than the image view it crops what can't fit.
Here are all the contentModes directly from a Obj-C and Swift source files:
typedef NS_ENUM(NSInteger, UIViewContentMode) {
UIViewContentModeScaleToFill,
UIViewContentModeScaleAspectFit, // contents scaled to fit with fixed aspect. remainder is transparent
UIViewContentModeScaleAspectFill, // contents scaled to fill with fixed aspect. some portion of content may be clipped.
UIViewContentModeRedraw, // redraw on bounds change (calls -setNeedsDisplay)
UIViewContentModeCenter, // contents remain same size. positioned adjusted.
UIViewContentModeTop,
UIViewContentModeBottom,
UIViewContentModeLeft,
UIViewContentModeRight,
UIViewContentModeTopLeft,
UIViewContentModeTopRight,
UIViewContentModeBottomLeft,
UIViewContentModeBottomRight,
};
public enum UIViewContentMode : Int {
case scaleToFill
case scaleAspectFit // contents scaled to fit with fixed aspect. remainder is transparent
case scaleAspectFill // contents scaled to fill with fixed aspect. some portion of content may be clipped.
case redraw // redraw on bounds change (calls -setNeedsDisplay)
case center // contents remain same size. positioned adjusted.
case top
case bottom
case left
case right
case topLeft
case topRight
case bottomLeft
case bottomRight
}
EDIT:
Since I see you're also interested in changing the dimensions of the imageView itself ("to leave more room for the text") what I would suggest is actually, either in storyboard or programmatically use AutoLayout to add your own imageView and have it sized and placed how you want it, instead of using the default imageView on a cell which is meant as a convenient/standardized tool.
If you are unfamiliar this I would google for an AutoLayout tutorial. Or maybe "using AutoLayout to create custom UITableViewCell"
If you dont actually want to create your own subclass you can try setting the `cell.imageView.frame = ..." somewhere to manually resize it to what you want, then setting its content mode to make sure the image fits nicely still.
See this question: How do I make UITableViewCell's ImageView a fixed size even when the image is smaller

Found an answer to my own question, with credit due to Paul's answer from this question: How to resize a cell.imageView in a TableView and apply tintColor in Swift
CGSize itemSize = CGSizeMake(50, 50);
UIGraphicsBeginImageContextWithOptions(itemSize, false, 0);
CGRect imageRect = CGRectMake(0, 0, itemSize.width, itemSize.height);
[cell.imageView.image drawInRect:imageRect];
cell.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I still don't know why the old CGAffineTransformMakeScale doesn't work anymore, but this gets the job done.

Related

Position UIImageView's image at top

I've got a UIImageView which has a height greater than its UIImage. It is scaling the image to it's width, but since it's height is greater, it is showing the rest of the UIImageView as transparent (what you would expect from UIViewContentModeScaleAspectFit, which is what the UIImageView's contentMode is set to)
However, it is making the top and bottom of the UIImage transparent, basically, positioning the image in the center of itself. How can I get it to position itself at the top? When I use UIViewContentModeTop, it makes the image too large, so that doesn't work for me. I want some sort of way to scale it just as it does with UIVIewContentModeScaleAspectFill but tell it to also position the scaled image at the top of itself. Anyone have any ideas on how to do that?
I would also be able to fix the issue by just trimming the UIImageView's height to be equal to what the UIImage is once it's been stretched to the boundaries of its superview, but that seems like a more complex solution.
try something like,
UIImage *img = [UIImage imageNamed#"yourImageName.jpeg"];
yourImageView.contentMode = UIViewContentModeScaleAspectFit;
yourImageView.clipsToBounds = YES;
[yourImageView setImage:img];

iOS: Solid Border Outside UIView

A layer's borderWidth and borderColor properties draw a border inside the view. Remykits pointed this out here.
A layer's shadow... properties cannot be used to create a border that both appears on all four sides and is opaque for reasons I showed here.
What I failed to specify in that question (and the reason I've opened a new one) is that I want the border to be outside the view. Increasing the frame of the view to compensate for the space lost, as has been suggested, doesn't work; I'm using a UIImageView, so even if the frame is increased, the image is still cropped.
Another suggestion was to change the contentMode of the UIImageView to .Center, in combination with changing the size of the view, but this doesn't work as the view then isn't the proper size.
The solution I first thought of was to create another UIView "behind" this UIImageView, and give it a backgroundColor to mimic the effect of a border. I also thought of creating a custom subclass of UImageView. Both courses of action, however, involve making calculations based on the frame of the view. I've had many problems with the frame not being set by AutoLayout at the proper time, etc.
Other things that come to mind are digitally adding a border to the image or positioning the image in a specific part of the UIImageView. (My attempt at the latter was imageView.layer.contentsRect = CGRectInset(imageView.bounds, 4, 4), which resulted in a strangely pixellated image.)
To be clear, what I'm looking for is this:
It really feels like there should be a simpler way to do this than creating a new class or view. Any help appreciated.
Aha! Stitching together aykutt's comment about resizing the image and changing the conentMode, Paul Lynch's answer about resizing images, and rene's (life-saving) answer about what to do your subviews actually aren't laid out in viewDidLayoutSubviews:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.myContainer.setNeedsLayout()
self.myContainer.layoutIfNeeded()
var width: CGFloat = 4 //the same width used for the border of the imageView
var rect = CGRectInset(imageView.bounds, width, width)
var size = CGSizeMake(rect.width, rect.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
image.drawInRect(CGRectMake(0, 0, size.width, size.height))
var new = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.imageView.contentMode = .Center
self.imageView.image = new
}

Autolayout: UIImageView not rotating with device orientation

There's probably a dozen SO questions with similar titles, and as far as I can see, I've incorporated the advice from every one of them, with no luck. When I rotate the device from portrait to landscape, I want to change the background image. However, in every experiment I have tried, the UIImageView in landscape remains portrait sized.
I am using Autolayout, configured in IB like so:
My view hierarchy is configured like so:
When I rotate the device, I want to rotate everything in UIView viewBackground (the image and all of the buttons). I believe I can manage the button movements through constraints, but need to rotate UIImageView image view background myself. So, I added the following code:
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
int scaleFactor = self.traitCollection.displayScale;
NSString *source = #"drawn";
NSString *orientation;
if (size.width > size.height)
{
orientation = #"Landscape";
}
else
{
orientation = #"Portrait";
}
NSString *platform;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
platform = #"iPad";
}
else
{
platform = #"iPhone";
}
NSString *filename = [NSString stringWithFormat:#"%# %# %# %.0fx%.0f.png", source, platform, orientation, size.width * scaleFactor, size.height * scaleFactor];
// CONFIRMED: we have assembled the correct new image name.
viewBackground.frame = CGRectMake(0, 0, size.width * scaleFactor, size.height * scaleFactor);
viewBackground.autoresizesSubviews = YES;
viewBackground.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imageViewBackground.autoresizesSubviews = YES;
imageViewBackground.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imageViewBackground.image = [UIImage imageNamed:filename];
}
The problem: The correct image appears on the screen, but as as mentioned above, it still has the portrait dimensions. I'm certain the image changes as the artwork is significantly different, with elements being stacked horizontally versus vertically. But the new picture is cut off horizontally in landscape mode.
I have tried putting all sorts of wild values into newRect, and none of them make any difference. The image never actually moves, even if I radically change the origin in newRect. so my current theory is that my changes to the view sizes are being ignored/over written.
The Question: What am I missing that's preventing the resizing of the image to landscape mode? Is there some other auto sizing aspect I'm not addressing?
So, the problem turned out to be yet another variable in the saga. There also must be a constraint on the UIImageView that is 0 on each side, with "Constrain to Margins unchecked." Apparently, when I did that step earlier, it didn't actually take.
I have to admit, though, I really don't understand what that constraint is doing for me. It clearly makes the rotation work, but I don't get why. Since that's technically the answer to my original question, I'll gladly award the answer if someone can explain how this constraint enables this scenario.
EDIT:
In case anyone stumbles upon this answer in the future... I see now that setting the aforementioned constraint with all 0 buffers between the UIImageView and the UIView pins the edges of UIImageView to the edges of the UIView. When the device rotates, the viewController resizes the UIView, and with this constraint, the UIImageView resizes also. I was able to remove the majority of my code. The only code I need is to select a portrait or landscape image, and I was able to remove everything that resized the UIView and UIImageView.
The image now changes size properly when rotating just by using the one constraint. I only need code to decide whether to show a landscape or portrait background. (And I vastly simplified that code by storing my images in an asset catalog so the code just selects the name of "portrait" or "landscape", but the size of the image is auto selected based on the device).

need a very tiny (rectangular in shape) overlay over UIImagePickerController, and then crop the image accordingly - UPDATED

In my application, i need the user to take a snap of only a 10 letter word (using overlay, which should be right in the centre of the screen of the UIImagePicker), and then in need to show him that image (only the part of the image covered by that rectangle). So, I need to crop that image according to the overlay.
Here, i have taken a picture using UIImagePickerControl. Now, i want to see the dimensions of the image that i have taken..
UIImage *imageToprocess = [info objectForKey:UIImagePickerControllerOriginalImage];
NSLog(#"image width %f", imageToprocess.size.width);
NSLog(#"image height %f", imageToprocess.size.height);
I see the following result on console.. But how is this possible. the dimensions of the image is exceeding the dimension of the iPhone screen size.. (which is 320, 568)
UsingTesseractOCR[524:60b] image width 2448.000000
2013-12-17 16:02:18.962 UsingTesseractOCR[524:60b] image height 3264.000000
Can anybody help me out here?? I have gone through several questions here, but did not understand how to do it.
Please help..
Refer this sample code for image capturing and cropping.
https://github.com/kishikawakatsumi/CropImageSample
For creating overlay, first create a custom view (of full dimensions of camera preview) and add an transparent image with just a rectangle in its background. use this view as overlay view.
myview =[[UIImageView alloc]init];
myview.frame=CGRectMake(0, 0, 320, 431);
// why 431? bcoz height = height of device - height of tabbar present in the
bottom for camera controls of picker
//for iphone 4 ,480-49
myview.backgroundColor =[UIColor clearColor];
myview.opaque = NO;
myview.image =[UIImage imageNamed:#"A45Box.png"];
myview.userInteractionEnabled =YES;
note that you create a background image appropriately (means dimensions). You can also draw rectangle programmatically but this is much easy way.
Secondly, talking about your cropping issue, you have to get your hands dirty....Try these links for help
https://github.com/iosdeveloper/ImageCropper
https://github.com/barrettj/BJImageCropper
https://github.com/ardalahmet/SSPhotoCropperViewController

How to truncate a UIImage in iOS

How can I truncate the left side of an image stored in a UIImage object. Basically in certain situations I just want to show part of an image.
How can I do this on with the iOS sdk?
P.S. I tried changing the frame size of the UIImage but that just scales the image and distorts it.
A very simple way is to load the image into a UIImageView, and then add the view to another view. You can then position the image view so that its .frame.origin.x property is negative, which will place it off to the left. The parent view needs to have setMasksToBounds:YES called on it, or else the image view will still be fully-visible.
There are many other ways to achieve this effect as well, but this may be the simplest for you to implement.
to crop a UIImage, you can use one of the UIImage categories available out there, such as http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/
For example, this frame will remove 100 pixel from the left side of a 200x200 pixel UIImage
CGRect clippedRect = CGRectMake(100, 0, 100, 200);
UIImage *cropped = [self imageByCropping:lightsOnImage toRect:clippedRect];

Resources