How to Make Case Override Previous Case - ios

I have a number of cases that generate a different image for each case. The problem is, the images seem to stack once they are generated. How can I set each case to override the previous image?
- (void)setTileValue:(NSInteger)tileValue {
_tileValue = tileValue;
self.numberLabel.text = [#(tileValue) stringValue];
UIImageView *backgroundView = [self backgroundView:[#(tileValue) intValue]];
[self.numberLabel addSubview:backgroundView];
self.value = tileValue;
}
- (UIImageView *)backgroundView:(NSUInteger)value {
switch (value) {
case 1:
return [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background"]]; // light gray
case 2:
return [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background1"]]; // gray
case 4:
return [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background2"]]; // gark gray
case 8:
return [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background3"]]; // red
case 16:
return [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background4"]]; // orange
default:
return [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"background"]];
}
}
UPDATED CODE: So the program is creating a new image each time with the initWithImage. I set the return to only return the UIImage now. Why doesn't this code fix the issue either?
- (void)setTileValue:(NSInteger)tileValue {
_tileValue = tileValue;
self.numberLabel.text = [#(tileValue) stringValue];
// UIImageView *backgroundView = [self backgroundView:[#(tileValue) intValue]];
UIImageView *backgroundView = [[UIImageView alloc] initWithImage:[self tileBG:[#(tileValue) intValue]]]; [self.numberLabel addSubview:backgroundView];
self.numberLabel.backgroundColor = [self tileColorForValue:[#(tileValue) intValue]];
self.backgroundColor = [self tileColorForValue:[#(tileValue) intValue]];
self.numberLabel.textColor = [self numberColorForValue:[#(tileValue) intValue]];
self.value = tileValue;
}
- (UIColor *)defaultBackgroundColor {
return [UIColor lightGrayColor];
}
- (UIColor *)defaultNumberColor {
return [UIColor colorWithWhite:0.0 alpha:0.0];
}
- (UIImage *)tileBG:(NSUInteger)value {
switch (value) {
case 1:
return [UIImage imageNamed:#"background"]; // light gray
case 2:
return [UIImage imageNamed:#"background1"]; // gray
case 4:
return [UIImage imageNamed:#"background2"]; // gark gray
case 8:
return [UIImage imageNamed:#"background3"]; // red
case 16:
return [UIImage imageNamed:#"background4"]; // red
case 32:
return [UIImage imageNamed:#"background5"]; // red
default:
return [UIImage imageNamed:#"background"]; // red
}
}

You're making a new image view every time and adding it. Eventually this could cause your app to crash due to memory use (tons of image views can be expensice).
Make the image view once, and set its image accordingly (just return an image from your switch statement), or remove the previous image view before adding a new one.
You need to keep a reference to the image view somewhere, ideally a property on whatever class this is. Then, just set its image property. Don't create a new image view here, and don't add any subviews. The image view should be created once, in your init method.

please read my comments above. then modify your setTitleCode to look like this.
- (void)setTileValue:(NSInteger)tileValue
{
_tileValue = tileValue;
self.numberLabel.text = [#(tileValue) stringValue];
UIImageView *backgroundView = (UIImageView *)[self.numberLabel viewWithTag:1000]; // edited code to avoid warning
if (!backgroundView)
{
backgroundView = [[UIImageView alloc] initWithImage:[self tileBG:[#(tileValue) intValue]]];
backgroundView.tag = 1000;
[self.numberLabel addSubview:backgroundView];
}
backgroundView.image = [self tileBG:[#(tileValue) intValue]];
self.numberLabel.backgroundColor = [self tileColorForValue:[#(tileValue) intValue]];
self.backgroundColor = [self tileColorForValue:[#(tileValue) intValue]];
self.numberLabel.textColor = [self numberColorForValue:[#(tileValue) intValue]];
self.value = tileValue;
}

If you mean that after the switch it's creating multiple images, then try using a
break();
But the safe things to do it to create an imageView and init it, then set its image in the switch statement, that way even if it gets placed more than one, it will keep the last reference.

Related

dynamically get the image from different resource folder iOS

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

Objective - C: UITableView Content Changing on Scroll

I'm using the QuickBlox Framework to build a chatting application. Currently, when the chat view opens up, everything looks great.
However, when the users begins to scroll up and down the chat history, some of the cells begin to change (for example, they'll show an image which should be placed in a different row).
Below is my code for cellForRowAtIndexPath, if anyone can tell me what I'm doing wrong
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
QBChatMessage *message = [[ChatService shared] messagsForDialogId:self.dialog.ID][indexPath.row];
if (message.attachments.count > 0) {
ImageTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ImageCellIdentifier];
[cell configureCellWithImage:message];
cell.backgroundColor = [UIColor whiteColor];
return cell;
} else {
ChatMessageTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ChatMessageCellIdentifier];
[cell configureCellWithMessage:message];
cell.backgroundColor = [UIColor whiteColor];
return cell;
}
}
EDIT Please see below my ImageTableViewCell configureCellWithImage method:
- (void) configureCellWithImage:(QBChatMessage*)message {
NSString *time = [message.dateSent timeAgoSinceNow];
if ([QBSession currentSession].currentUser.ID == message.senderID) {
// Message was sent by me
NSData *imageData = [FTWCache objectForKey:[NSString stringWithFormat:#"%#", [message.attachments[0] valueForKey:#"ID"]]];
if (imageData) {
// image is already downloaded
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
UIImageView *cellImage = [[UIImageView alloc] init];
[self.backgroundImageView setFrame:CGRectMake(320-155, 10, 140, 140)];
cellImage.frame = CGRectMake(7, 7, 120, 120);
[cellImage setContentMode:UIViewContentModeScaleAspectFill];
cellImage.clipsToBounds = YES;
cellImage.layer.cornerRadius = 5;
cellImage.image = image;
self.backgroundImageView.image = aquaBubble;
[self.backgroundImageView addSubview:cellImage];
[self.contentView addSubview:self.backgroundImageView];
});
} else {
// downloads the image and displays as above
}
} else {
// Message was sent by another user
NSData *imageData = [FTWCache objectForKey:[NSString stringWithFormat:#"%#", [message.attachments[0] valueForKey:#"ID"]]];
if (imageData) {
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
UIImageView *cellImage = [[UIImageView alloc] init];
[self.backgroundImageView setFrame:CGRectMake(padding/2, padding+5, 140, 140)];
cellImage.frame = CGRectMake(13, 7, 120, 120);
[cellImage setContentMode:UIViewContentModeScaleAspectFill];
cellImage.layer.cornerRadius = 5;
cellImage.clipsToBounds = YES;
cellImage.image = image;
self.timeLabel.frame = CGRectMake(20, self.backgroundImageView.frame.size.height + 20, 80, 20);
self.timeLabel.text = [NSString stringWithFormat:#"%#", time];
[self.timeLabel setFont:[UIFont systemFontOfSize:10.0]];
[self.timeLabel setTextColor:[UIColor blackColor]];
[self.contentView addSubview:self.timeLabel];
self.nameAndDateLabel.textAlignment = NSTextAlignmentLeft;
QBUUser *sender = [ChatService shared].usersAsDictionary[#(message.senderID)];
NSInteger loginForColor = [sender.login integerValue];
loginForColor = loginForColor % 255;
self.nameAndDateLabel.text = [NSString stringWithFormat:#"%#", sender.fullName];
self.backgroundImageView.image = orangeBubble;
[self.backgroundImageView addSubview:cellImage];
[self.contentView addSubview:self.backgroundImageView];
});
} else {
// downloads the image and displays as above
}
}
}
Cells get reused. Therefore you must always set/reset all properties of the cell each time.
For every if statement that sets a cell's property, there must be an else statement that resets the same property - even if it just clears the value.
Also you must avoid adding subviews over and over each time the cell is used. You have code that creates and adds an image view to the cell. But you keep adding new image views over and over. Just add it once if needed. If it's already there, update it with the new image instead of adding a new one.
The error should be on the functions configureCellWithImage and configureCellWithMessage.
I didn't see the code of those functions, but i bet that you didn't clean the image content on the configureCellWithMessage.

UIimage will not move on btn press, what am i doing wrong?

I am trying to move a UIImage, first button press creates the image and second press moves it.
The image only needs to exist upon pressing the button.
In the simulator it creates the button and places it, the second time it click just doesn't do anything.
This is my Code
- (IBAction) btn:(id)sender {
UIImageView *myImage = [[UIImageView alloc] init];
myImage.image = [UIImage imageNamed:#"keyframe"];
if (startUp == 1){
//Create Image and add to view
myImage.frame = CGRectMake(200, 300, 10, 10);
myImage.image = [UIImage imageNamed:#"keyframe"];
[self.view addSubview:myImage];
//Set startUp to 0 and output rect value
startUp = 0;
NSLog(#"currentFrame %#", NSStringFromCGRect(myImage.frame));
}else if (startUp == 0){
//Change position, size and log to debug
myImage.frame = CGRectMake(500,100 ,20, 20);
NSLog(#"newFrame %#", NSStringFromCGRect(myImage.frame));
}
}
How do you programmatically move a programmatically added UIimage?
I tried changing the center value but that doesn't work either.
Try something like this – tested and working sample:
#import "ViewController.h"
#interface ViewController () {
BOOL startUp;
UIImageView *myImage;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
startUp = YES;
}
- (IBAction)doWork:(id)sender {
if (startUp) {
UIImage *img = [UIImage imageNamed: #"keyframe"];
myImage = [[UIImageView alloc] initWithImage: img];
[myImage sizeToFit];
[myImage setCenter: CGPointMake(200, 300)];
[self.view addSubview: myImage];
startUp = NO;
} else {
[myImage setCenter: CGPointMake(400, 500)];
}
}
#end

Problems with changing the image property of a UIImageView

I have a UIImageView that when a function called I want to change to a different ("active") image and when another called change back to the image before. This is the code:
- (NavButton *)initWithFrame:(CGRect *)fr andImage:(UIImage *)img andActiveImage:(UIImage *)acImg {
NavButton *a = [[NavButton alloc] initWithFrame:*fr];
[a setBackgroundColor:[UIColor clearColor]];
UIImageView *aImg = [[UIImageView alloc] initWithFrame:CGRectMake(8.5, 8.5, 28, 28)];
aImg.tag = 13;
aImg.image = img;
self.orginalImage = img;
self.activeImage = acImg;
[a addSubview:aImg];
return a;
}
- (void)setIsActive:(NSNumber *)isActive {
self.active = isActive;
if ([isActive isEqualToValue:[NSNumber numberWithBool:NO]]) {
[self undoActive];
} else {
[self redoActive];
}
}
- (void)undoActive {
UIImageView *a = (UIImageView *)[self viewWithTag:13];
a.image = self.orginalImage;
}
- (void)redoActive {
UIImageView *a = (UIImageView *)[self viewWithTag:13];
a.image = self.activeImage;
}
When I call [btn setIsActive:[NSNumber numberWithBool:YES]]; or [btn setIsActive:[NSNumber numberWithBool:NO]]; both times it removes the image, but when I don't call either the image stays there. So, how do I make it so when I call them it changes the images of the button to the correct image?
Instead of repeatedly assigning image to imageview, you can assign two images to the image view: one to "image" property and other to "highlightedImage" property. When you want to switch between the images, set the Boolean property "highlighted" as YES or NO.
It will be easier just to do your check as:
if (![isActive boolValue]) {
Then, do some debugging, add some breakpoints and / or logging. Check what values are actually being received. Are the flags set correctly. Are the images set correctly. Is anything nil.

Can I set image as a title to UINavigationBar?

Is it possible to set some image as title of Navigation bar?
I think NYTimes application used a Navigation bar and title is look like image file (the reason why it's seems UINavigationBar is because they use right button to search).
You can use an UIImageView for the UINavigationItem.titleView property, something like:
self.navigationItem.titleView = myImageView;
I find that a transparent .png at about 35px in height has worked well.
- (void)awakeFromNib {
//put logo image in the navigationBar
UIImageView* img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"logo.png"]];
self.navigationItem.titleView = img;
[img release];
}
You can do it right from storyboard (as of Xcode 7):
Create a view outside main view of view controller. It can be a nested view or just an image
Add navigation item to your view controller
Ctrl+ drag from navigation item and drop on outside view
4.select title view
I have created a custom category for UINavigationBar as follows
UINavigationBar+CustomImage.h
#import <UIKit/UIKit.h>
#interface UINavigationBar (CustomImage)
- (void) setBackgroundImage:(UIImage*)image;
- (void) clearBackgroundImage;
- (void) removeIfImage:(id)sender;
#end
UINavigationBar+CustomImage.m
#import "UINavigationBar+CustomImage.h"
#implementation UINavigationBar (CustomImage)
- (void) setBackgroundImage:(UIImage*)image {
if (image == NULL) return;
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(110,5,100,30);
[self addSubview:imageView];
[imageView release];
}
- (void) clearBackgroundImage {
NSArray *subviews = [self subviews];
for (int i=0; i<[subviews count]; i++) {
if ([[subviews objectAtIndex:i] isMemberOfClass:[UIImageView class]]) {
[[subviews objectAtIndex:i] removeFromSuperview];
}
}
}
#end
I invoke it from my UINavigationController
[[navController navigationBar] performSelectorInBackground:#selector(setBackgroundImage:) withObject:image];
This line will work for you, I always use this
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"imageNavBar.png"] forBarMetrics:UIBarMetricsDefault];
I modified the UINavigationBar+CustomImage.m to have the title still visible to the user. Just use insertSubview: atIndex: instead of addSubview:
UINavigationBar+CustomImage.m
#import "UINavigationBar+CustomImage.h"
#implementation UINavigationBar (CustomImage)
- (void) setBackgroundImage:(UIImage*)image {
if (image == NULL) return;
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 0, 320, 44);
[self insertSubview:imageView atIndex:0];
[imageView release];
}
- (void) clearBackgroundImage {
NSArray *subviews = [self subviews];
for (int i=0; i<[subviews count]; i++) {
if ([[subviews objectAtIndex:i] isMemberOfClass:[UIImageView class]]) {
[[subviews objectAtIndex:i] removeFromSuperview];
}
}
}
#end
This also works well too
[self.navigationController.navigationBar.topItem setTitleView:[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"YourLogo"]]];
Do it quickly using storyboard and #IBDesignable:
#IBDesignable class AttributedNavigationBar: UINavigationBar {
#IBInspectable var imageTitle: UIImage? = nil {
didSet {
guard let imageTitle = imageTitle else {
topItem?.titleView = nil
return
}
let imageView = UIImageView(image: imageTitle)
imageView.frame = CGRect(x: 0, y: 0, width: 40, height: 30)
imageView.contentMode = .scaleAspectFit
topItem?.titleView = imageView
}
}
}
Then in attributes inspector just select an image:
and wait a second for result:
So setting view is there where it should be... in storyboard.
For those who have the same error but in Xamarin Forms, the solution is to create a Renderer in iOS app and set the image like so :
[assembly: Xamarin.Forms.ExportRenderer(typeof(Xamarin.Forms.Page), typeof(MyApp.Renderers.NavigationPageRenderer))]
namespace MyApp.Renderers
{
#region using
using UIKit;
using Xamarin.Forms.Platform.iOS;
#endregion
public class NavigationPageRenderer : PageRenderer
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
SetTitleImage();
}
private void SetTitleImage()
{
UIImage logoImage = UIImage.FromFile(ResourceFiles.ImageResources.LogoImageName);
UIImageView logoImageView = new UIImageView(logoImage);
if (this.NavigationController != null)
{
this.NavigationController.NavigationBar.TopItem.TitleView = logoImageView;
}
}
}
}
Hope it helps someone!
I modified the UINavigationBar+CustomImage code to properly work without leaking memory.
- (void)setBackgroundImage:(UIImage *)image
{
if (! image) return;
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
[self addSubview:imageView];
[imageView release];
}
- (void) clearBackgroundImage
{
// This runs on a separate thread, so give it it's own pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *mySubviews = self.subviews;
// Move in reverse direction as not to upset the order of elements in the array
for (int i = [mySubviews count] - 1; i >= 0; i--)
{
if ([[mySubviews objectAtIndex:i] isMemberOfClass:[UIImageView class]])
{
[[mySubviews objectAtIndex:i] removeFromSuperview];
}
}
[pool release];
}
The following is how you would do this in (Xamarin's) MonoTouch with C#.NET
Create a UIViewConvrtoller that is in a NavigationController then call this at any time:
someNiceViewControllerYouMade.NavigationController.NavigationBar
.InsertSubview(new UIImageView
(MediaProvider.GetImage(ImageGeneral.navBar_667x44)),0);
Note: MediaProvider is just a class that fetches images.
This example allows for the view to fill the full Navigation Bar , and lets the text for the items caption appear too.
If your buttons disappear when you navigate back and forth the navigation, this fixed it for me:
NSArray *mySubviews = navigationBar.subviews;
UIImageView *iv = nil;
// Move in reverse direction as not to upset the order of elements in the array
for (int i = [mySubviews count] - 1; i >= 0; i--)
{
if ([[mySubviews objectAtIndex:i] isMemberOfClass:[UIImageView class]])
{
NSLog(#"found background at index %d",i);
iv = [mySubviews objectAtIndex:i];
[[mySubviews objectAtIndex:i] removeFromSuperview];
[navigationBar insertSubview:iv atIndex:0];
}
}
Just use
[navController.navigationBar insertSubview:myImage atIndex:0] ;
where myImage is of type UIImageView
and navController is of type UINavigationController
ios5.0 introduced a heap of features to customise the appearance of standard elements. If you didn't want to use an ImageView for the title, an alternative would be to customise the appearance of all UINavbars using a background image and a custom font/colour.
- (void) customiseMyNav
{
// Create resizable images
UIImage *portraitImage = [[UIImage imageNamed:#"nav_bar_bg_portrait"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
UIImage *landscapeImage = [[UIImage imageNamed:#"nav_bar_bg_landscape"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
// Set the background image
[[UINavigationBar appearance] setBackgroundImage:portraitImage forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundImage:landscapeImage forBarMetrics:UIBarMetricsLandscapePhone];
// set the title appearance
[[UINavigationBar appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor colorWithRed:50.0/255.0 green:150.0/255.0 blue:100/255.0 alpha:1.0],
UITextAttributeTextColor,
[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.6],
UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0, -1)],
UITextAttributeTextShadowOffset,
[UIFont fontWithName:#"Arial-Bold" size:0.0],
UITextAttributeFont,
nil]];
}
In MonoTouch you can use this:
this.NavigationItem.TitleView = myImageView;
Add image to naviagtionBar with SWIFT that scales to fit and clips to bounds. You can call this function inside the view controllers viewDidLoad() function.
func setupNavigationBarWithTitleImage(titleImage: UIImage) {
let imageView = UIImageView(image: titleImage)
imageView.contentMode = .ScaleAspectFit
imageView.clipsToBounds = true
navigationItem.titleView = imageView
}

Resources