I've got a header/brand image which changes between iPad and iPhone, but will not change the picture when changing from portrait to landscape, which is really important that it does.
I have this HeaderView Class, which is called by tableViewControllers like this:
self.tableView.tableHeaderView = [[HeaderView alloc] initWithText:#""];
which holds a UIImageView:
#interface HeaderView : UIImageView{
}
- (id)initWithText:(NSString*)text;
- (void)setText:(NSString*)text;
#end
For the M file, we find where I'm not getting the result I want:
#import "HeaderView.h"
#define IDIOM UI_USER_INTERFACE_IDIOM()
#define IPAD UIUserInterfaceIdiomPad
#interface HeaderView()
{
UILabel*label;
}
#end
#implementation HeaderView
- (id)initWithText:(NSString*)text
{
UIImage* img = [UIImage imageNamed:#"WashU.png"];
UIImage* iPhonePortrait = [UIImage imageNamed:#"WashU2.png"];
UIImage* image = [[UIImage alloc] init];
UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
//different header image for different devices...
if(IDIOM==IPAD){
image = img;
}
else{
if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
image = iPhonePortrait;
}
else if(UIInterfaceOrientationIsLandscape(interfaceOrientation))
{
iPhonePortrait = nil;
image = img;
}
}
[headerImageView setImage:image];
if (self = [super initWithImage:image]){
}
return self;
}
I also have added these methods:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
-(BOOL)shouldAutorotate {
return YES;
}
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
I'm sure its a classic sort of question, but I'm reasonably stumped. Also, if I remove
[headerImageView setImage:image];
, and
[self addSubview:headerImageView];
, the image still shows up, which means that
if (self = [super initWithImage:image])
is doing all the display work.
didRotateFromInterfaceOrientation is sent to your view controller after rotation, you can implement that to change your image.
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
...change your image here
}
As your code, you do not need allocate (UIImage*)image property, because you will assign (UIImage*)img or (UIImage*)iPhonePortrait. And should assign image to headerImageView.image.
[headerImageView setImage:image];
You are not actually assigning the image to the imageView. Add:
headerImageView.image = image;
somewhere after 'image' has been set (based on iPad vs iPhone and Portrait vs Landscape).
Related
Currently I have the image folder the paths is Resource/images and inside the images folder there are several images, I would like to create dark mode using the same image name but the image are different in dark mode style and normal style. example(icon in dark mode is white but in normal mode is black)
I would like to know if I create 2 folder inside Resource/images/imageOneFolder and Resource/images/imageTwoFolder, how can I access the specific path to get the image.
Thanks
first you need to organize your icons in a better way for example:
Resources/images/black/myicon_black.png
Resources/images/white/myicon_white.png
Having this level of organization resolve the problem is very easy, I provide you two ways to resolve using the next logic:
#interface MyStructObject : NSObject
#property (nonatomic) NSString *imageName, *imageExtension, *fullImageName;
#end
#interface MyViewController : UIViewController
#end
#implementation MyViewController
// For this short version your icons needs to be white or black
// With the next code you can change the color of your icon
// Example: If dark mode active you need icons with whiteColor
// if not dark mode you need icons with blackColor
- (void)didExecuteShortVersion
{
// Initial path document or bundle
NSString *resourcesPath = #"Resources/images";
// Getting objects from array or your own struct
MyStructObject *myItem = [MyStructObject new];
// The image full path
NSString *fullImagePath = [NSString stringWithFormat: #"%#/%#", resourcesPath, myItem.fullImageName];
// Image Object
UIImage *imageIcon = [UIImage imageWithContentsOfFile: fullImagePath];
// Image Container
UIImageView *myImageView = [[UIImageView alloc] initWithFrame: CGRectZero];
[myImageView setImage: imageIcon];
myImageView.image = [myImageView.image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
if (#available(iOS 12.0, *)) {
if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
[myImageView setTintColor: [UIColor whiteColor]];
}
else {
[myImageView setTintColor: [UIColor blackColor]];
}
}
else {
// Dark mode is not available
[myImageView setTintColor: [UIColor blackColor]];
}
// Adding view
[self.view addSubview: myImageView];
}
#pragma mark - Life Cycle
- (void)viewDidLoad
{
// Initial path document or bundle
NSString *resourcesPath = #"Resources/images";
// The image full path
NSString *fullImagePath = nil;
// Getting objects from array or your own struct
MyStructObject *myItem = [MyStructObject new];
if (#available(iOS 12.0, *)) {
if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
NSLog(#"Dark Mode Active");
// Assuming your struct only has the first name of icon
// Example: myItem.imageName -> myicon
// Adding the last path of name to match icon _black -> myicon_black
// If you have different kind of extension you can improve
// the logic of this
fullImagePath = [NSString stringWithFormat: #"%#/black/%#_black.%#", resourcesPath, myItem.imageName, myItem.imageExtension];
}
else {
NSLog(#"White Mode Active");
fullImagePath = [NSString stringWithFormat: #"%#/white/%#_white.%#", resourcesPath, myItem.imageName, myItem.imageExtension];
}
} else {
// Dark mode is not available
fullImagePath = [NSString stringWithFormat: #"%#/default/%#_default.%#", resourcesPath, myItem.imageName, myItem.imageExtension];
}
if (fullImagePath != nil) {
UIImage *imageIcon = [UIImage imageWithContentsOfFile: fullImagePath];
// Change the CGRect
UIImageView *myImageView = [[UIImageView alloc] initWithFrame: CGRectZero];
[myImageView setImage: imageIcon];
// Add myImageView to the UIView
[self.view addSubview: myImageView];
}
}
#end
i have a map view in my view controller, when i make a pin on the desired place i give my own image despite of the default image , but when i run and check the map it always shows default pin in my map instead of my image that i have passed. My code is this,
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
MKAnnotationView *view=[self.mapView dequeueReusableAnnotationViewWithIdentifier:#"annoView"];
if (!view) {
view=[[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:#"annoView"];
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}else{
view.image=[UIImage imageNamed:#"car_marker.png"];
view.canShowCallout=YES;
}
}
return view;
}
MapPin *pin=[[MapPin alloc]init];
pin.title=loc[#"name"];
pin.subtitle=nil;
pin.coordinate=annoCordinate;
[self.mapView addAnnotation:pin];
[self.mapView setCenterCoordinate:pin.coordinate animated:YES];
This is very easy to accomplish, you just need to subclass MKAnnotationView and add a custom image view to it. A good example can be found here.
In case the link dies, I have also included the code snippet below, please do show the OP some love though!
#interface TStickerAnnotationView : MKAnnotationView
#property(nonatomic) float stickerColor;
#end
#interface TStickerAnnotationView () {
UIImageView *_imageView;
TCircleView *_circleView;
}
#end
#implementation TStickerAnnotationView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// make sure the x and y of the CGRect are half it's
// width and height, so the callout shows when user clicks
// in the middle of the image
CGRect viewRect = CGRectMake(-30, -30, 60, 60);
TCircleView* circleView = [[TCircleView alloc] initWithFrame:viewRect];
_circleView = circleView;
[self addSubview:circleView];
UIImageView* imageView = [[UIImageView alloc] initWithFrame:viewRect];
// keeps the image dimensions correct
// so if you have a rectangle image, it will show up as a rectangle,
// instead of being resized into a square
imageView.contentMode = UIViewContentModeScaleAspectFit;
_imageView = imageView;
[self addSubview:imageView];
}
return self;
}
- (void)setImage:(UIImage *)image
{
// when an image is set for the annotation view,
// it actually adds the image to the image view
_imageView.image = image;
}
- (void)stickerColor:(float)color {
_circleView.green = color;
[_circleView setNeedsDisplay];
}
When I take a picture with the phone in Portrait mode, using a UIImagePickerController, the UIImage item that is returned has the top of the image facing left and an imageOrientation property of UIImageOrientationRight , // 90 deg CCW, which is as expected (I think).
When I share the image via a UIActivityViewController, all activities seem to behave correctly except for the Copy activity. When I paste the image into another application (for instance, Messages), the image seems to be ignoring the imageOrientation property.
Has anyone else seen this / found a workaround?
Updated with complete code: (project contains storyboard with a single button mapped to self.takeImageButton and - (IBAction)takeImageAndShare:(id)sender;)
#import "ViewController.h"
#interface ViewController () <UIImagePickerControllerDelegate,UINavigationControllerDelegate>
#property (weak, nonatomic) IBOutlet UIButton *takeImageButton;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)takeImageAndShare:(id)sender {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.popoverPresentationController.sourceView = self.takeImageButton;
[self presentViewController:imagePicker animated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *chosenImage = info[UIImagePickerControllerOriginalImage];
[picker dismissViewControllerAnimated:YES completion:NULL];
NSLog(#"Image Orientation: %li",chosenImage.imageOrientation);
// Now share the selected image
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[chosenImage] applicationActivities:nil];
activityViewController.modalPresentationStyle = UIModalPresentationPopover;
activityViewController.popoverPresentationController.sourceView = self.takeImageButton;
[self presentViewController:activityViewController animated:YES completion:nil];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;
{
[picker dismissViewControllerAnimated:YES completion:NULL];
}
#end
If you run this code, take a photo with the phone in Portrait (.imageOrientation is 3 = UIImageOrientationRight) and select share activities like Messages, Save Image, etc., the image orientation is correct. If you select the copy activity, the image that gets pasted elsewhere is rotated (top of the image is to the left).
Submitted as Radar 19456881. Complete project is available here.
By Default capture image orientation behavior is UIImageOrientationRight, sp you have to set capture image orientation is
[UIDevice currentDevice].orientation
Based on this post, I decided to create my own copy activity:
//
// PhotoActivityCopy.m
//
// Created by Jeff Vautin on 1/13/15.
// Copyright (c) 2015 Jeff Vautin. All rights reserved.
//
#import "PhotoActivityCopy.h"
#import "ImageKit.h"
#import MobileCoreServices;
#interface PhotoActivityCopy ()
#property (strong,nonatomic) NSData *imageJPEGData;
#end
#implementation PhotoActivityCopy
NSString *PhotoActivityCopyActivityType = #"com.me.uiactivitytype.copy";
NSString *PhotoActivityCopyActivityTitle = #"Copy";
+ (UIActivityCategory)activityCategory
{
return UIActivityCategoryAction;
}
- (NSString *)activityType
{
return PhotoActivityCopyActivityType;
}
- (NSString *)activityTitle
{
return PhotoActivityCopyActivityTitle;
}
- (UIImage *)activityImage
{
CGSize imageSize;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
imageSize = CGSizeMake(76.0, 76.0);
} else {
imageSize = CGSizeMake(60.0, 60.0);
}
return [ImageKit imageOfIconCopyWithExportSize:imageSize];
}
- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems
{
BOOL canPerform = NO;
if ([activityItems count] > 1) {
canPerform = NO;
} else if ([[activityItems firstObject] isKindOfClass:[UIImage class]]) {
canPerform = YES;
}
return canPerform;
}
- (void)prepareWithActivityItems:(NSArray *)activityItems
{
self.imageJPEGData = UIImageJPEGRepresentation(activityItems[0], 1.0);
}
- (void)performActivity
{
[[UIPasteboard generalPasteboard] setData:self.imageJPEGData forPasteboardType:(id)kUTTypeJPEG];
[self activityDidFinish:YES];
}
#end
And then I excluded the native copy activity:
PhotoActivityCopy *copyActivity = [[PhotoActivityCopy alloc] init];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[chosenImage] applicationActivities:#[copyActivity]];
activityViewController.excludedActivityTypes = #[UIActivityTypeCopyToPasteboard];
I've implemented a custom (blurred) background for a modal view controller on iPad. Here's how I do it: in the presented VC's viewWillShow: I take a snapshot image of the presenting VC's view, blur it, and add a UIImage view on top of the presenting VC. This works well.
However, when I rotate the device while the modal is showing, the blurred image gets out of sync with the view controller it represents. The image gets stretched to fill the screen, but the view controller doesn't resize its views the same way. So when the modal is dismissed and the blur goes away, the transition looks bad.
I've tried taking another snapshot in didRotateFromInterfaceOrientation:, and replacing the blurred image, but that didn't work.
Any advice on how to solve this?
UPDATE: a sample project
My code (in the modal view controller):
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self drawBackgroundBlurView];
}
- (void)drawBackgroundBlurView
{
if(_blurModalBackground) {
[_backgroundBlurView removeFromSuperview];
CGRect backgroundFrame = self.presentingViewController.view.bounds;
_backgroundBlurView = [[UIImageView alloc] initWithFrame:backgroundFrame];
_backgroundBlurView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[_backgroundBlurView setImage:[STSUtils imageByBlurringView:self.presentingViewController.view]];
[self.presentingViewController.view addSubview:_backgroundBlurView];
}
}
Utils code
+ (UIImage *)imageByBlurringView:(UIView *)view
{
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
BOOL isPortrait = (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]));
CGRect frame;
if(isPortrait) {
frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.height, view.frame.size.width);
}
else {
frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height);
}
UIGraphicsBeginImageContextWithOptions(frame.size, NO, window.screen.scale);
[view drawViewHierarchyInRect:frame afterScreenUpdates:NO];
// Get the snapshot
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
// Apply blur
UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
UIImage *blurredSnapshotImage = [snapshotImage applyBlurWithRadius:8
tintColor:tintColor
saturationDeltaFactor:1.8
maskImage:nil];
UIGraphicsEndImageContext();
return blurredSnapshotImage;
}
I coded a simple example that takes a screenshot from presentingViewController and sets it as background image. Here is the implementaion of my modal view controller. And it works well (both on viewWillAppear and handles rotation properly). Could you please also post STSUtils code?
#import "ScreenshoterViewController.h"
#interface ScreenshoterViewController ()
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
- (IBAction)buttonBackPressed;
#end
#implementation ScreenshoterViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self updateImage];
}
- (void)updateImage
{
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.presentingViewController.view.layer renderInContext:context];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageView.image = img;
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[self updateImage];
}
- (IBAction)buttonBackPressed {
[self dismissViewControllerAnimated:YES
completion:NULL];
}
#end
Update
In your utils code just replace this
[view drawViewHierarchyInRect:frame afterScreenUpdates:NO];
with this
[view drawViewHierarchyInRect:frame afterScreenUpdates:YES];
From apple docs:
afterUpdates A Boolean value that indicates whether the snapshot
should be rendered after recent changes have been incorporated.
Specify the value NO if you want to render a snapshot in the view
hierarchy’s current state, which might not include recent changes.
So you were taking screenshot that did not included latest changes in the view.
When I show the iAd on _parentView(UIView) and create the image of this _parentView.
I show this image (resultingImage) on a UIImageView, then this image is blank(totally black).
How can I get the screenshot of iAd programmatically?
- (id)initWithView:(UIView *)currentView
{
self = [super init];
if (self) {
_parentView = currentView;
self.interstitial = [[ADInterstitialAd alloc] init];
self.interstitial.delegate = self;
}
return self;
}
- (void)interstitialAdDidLoad:(ADInterstitialAd *)interstitialAd
{
[interstitialAd presentInView:_parentView];
[self takeScreenshot];
}
- (void)takeScreenshot
{
CGRect rect = CGRectMake(0, 0, _parentView.frame.size.width, _parentView.frame.size.height);
UIGraphicsBeginImageContext(rect.size);
[_parentView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
Did you check if the device is a iPad?
Based on the Official Apple document.
It seems like you are doing it correctly. You might wana check if
[interstitialAd presentInView:_parentView];
returns a true of false, before continuing.
If that does not help, try using the delegate function:
- (void)interstitialAd:(ADInterstitialAd *)interstitialAd didFailWithError:(NSError *)error;
if it returns you any errors.
Edit:
Try using the root view controller from the key window. It works for me.
if([self.interstitial presentInView:_view])
{ NSLog(#"Able to present in view"); }
else
{ [self.interstitial presentFromViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; }