If no Image, change row cell height - ios

I'm using SDWebImage. I'm pulling the images in correctly from a web service API, but if the API I'm getting the response from doesn't have an image ("null"), I want to realign my Table View Cell.
ViewController.m
if ([fL.images count] == 0) {
//trying to figure out what to put here to change row height
}
else {
}
WebListCell.m
- (void)layoutSubviews {
[super layoutSubviews];
// (X, Y, Width, Height)
self.publishedLabel.frame = CGRectMake(300, 210, 20, 20);
self.imageView.frame = CGRectMake(0, 0, 320, 180);
self.headlineLabel.frame = CGRectMake(10, 210, 290, 40);
self.descriptionLabel.frame = CGRectMake(10, 250, 290, 30);
self.premiumLabel.frame = CGRectMake(260, 2, 60, 20);
}
My problem is I can't find a good "if" statement for when there is no image and I want to realign my Table View Cell.
I think I need to do something in WeblistCell.m and heightForRowAtIndexPath for this, but I'm stumped.
Any help would be appreciated!
Will post any necessary code needed!

Looks like you are pretty close to the solution for yourself. The key is the method -heightForRowAtIndexPath: - this needs to return the different height for the case when the row doesn't have an image. I'm not familiar with SDWebImage but if you are loading images from a web service of some kind, you should know which row (index) an image is for when you try to load it. So, if you go to retrieve an image and there isn't one (null), add that index to a mutable array to track missing image. Then your -heightForRowAtIndexpath: method just needs to check if the row property of the indexPath parameter exists in that array.

Related

Objective-C: add subview only work for one view

For each UIImageView, I want to add the label subview to it.
Here is my class inherited form UIImageView
-(instancetype)initWithFrame:(CGRect)frame
{
if (self=[super initWithFrame:frame]) {
self.categoryLabel=[[UILabel alloc]initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, 50)];
self.categoryLabel.textAlignment=NSTextAlignmentCenter;
self.categoryLabel.font=[UIFont systemFontOfSize:20];
self.categoryLabel.textColor=[UIColor whiteColor];
[self addSubview:self.categoryLabel];
NSLog(#"%#",self.subviews);
}
return self;
}
-(void)setModel:(HorizontalModel *)model
{
_model=model;
self.categoryLabel.text=self.model.category;
[self sd_setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"XXXXX%#",self.model.imgURL]] placeholderImage:[UIImage imageNamed:#"obama"]];
}
Here is my code in the view controller.
-(void)addImage:(NSNotification *)notification
{
self.HArrayLists=notification.userInfo[#"array"];
for (int i=0; i<[self.HArrayLists count]; i++) {
JTImageView *imageView=[[JTImageView alloc] initWithFrame:CGRectMake(i*310, 0, 300, 200)];
imageView.model=[HorizontalModel restaurantsDetailWithDict: self.HArrayLists[i]];
[self.mediaScrollView addSubview:imageView];
}
self.mediaScrollView.contentSize=CGSizeMake(310*[self.HArrayLists count], 0);
}
It turns out that only the first imageView shows a label, while the rest of the imageViews show only images.
I think the core of your problem is the line:
self.categoryLabel=[[UILabel alloc]initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, 50)];
You are offsetting the x and y positions of the label by the x and y values of the image. This will place them outside the area of the image and with the image clipping, make them invisible. I think the line should be
self.categoryLabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, 50)];
to place all the labels at the top left corner of each image.
Having said that there are also a number of recommendations I would like to offer.
Firstly make all variable names start with a lowercase. So self.HArrayLists should be self.hArrayLists.
Secondly try and make variable names match their contents. So again looking at self.HArrayLists, perhaps something like self.imageData.
Next I would have done the composition differently. I would have a UIView to which I add both the UILabel and UIImageView instances. Using a parent view like this to layout two sub views often makes life easier.
I would also look into using a UICollectionView and UICollectionViewController rather than a UIScrollView. It will take you a bit of work to get your heads around how collection views work. But you will gain in terms of performance and better layout management.
Finally, study up on constraints. They're an essential part of building modern apps that can easily adapt to different sized screens, rotation and layouts.
You need to set as categoryLabel's frame properly.
self.categoryLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, frame.origin.y, frame.size.width, 50)];

C# - Adding views programmatically of unknown size

I'm trying to add some views programmatically and from what I understand, you need to declare the size of view.
For example:
UITableView table = new UITableView(new CGRect(50, 0, 200, 100));
this.View.AddSubview(table);
But what if you don't know the size? What if this is dependent on dynamic data? Will the container simply expand as necessary?
I am trying to build a shopping cart interface. There are 3 main sections:
a TableView which contains the headers for the shopping basket (e.g. "Product Name", "Qty", etc).
A dynamic size Table which its size is dependent on the number of products contained in it.
Some checkout buttons underneath the cart.
Here is a really rough sample of what I'd like to see. The section in white is the dynamic area which will grow depending on how many items there are.
Currently what I'm doing is setting up one UITableView for the headings:
tableForHeaders = new UITableView(new CGRect(0, 0, screenWidth, 50));
tableForHeaders.SeparatorStyle = UITableViewCellSeparatorStyle.None;
tableForHeaders.Source = new UIShoppingCartHeaderTable.TableSource(headerRow);
this.View.AddSubview(tableForHeaders);
Then I have created another table for the line items (I won't bore you with my implementation of TableSource):
tableForRows = new UITableView(new CGRect(0, 50, screenWidth, this.View.Frame.GetMaxY()));
tableForRows.SeparatorStyle = UITableViewCellSeparatorStyle.None;
this.View.AddSubview(tableForRows);
And finally, I'm then trying to add the buttons in:
btnCheckout = new UIButton(new CGRect(0, 50 + tableForRows.ContentSize.Height, screenWidth, 50))
{
BackgroundColor = UIColor.Red
};
btnCheckout.SetTitle("Checkout", UIControlState.Normal);
btnCheckout.SetTitleColor(UIColor.White, UIControlState.Normal);
btnContinue = new UIButton(new CGRect(0, 100 + tableForRows.ContentSize.Height, screenWidth, 50))
{
BackgroundColor = UIColor.Red
};
btnContinue.SetTitle("Continue", UIControlState.Normal);
btnContinue.SetTitleColor(UIColor.White, UIControlState.Normal);
this.View.AddSubview(btnCheckout);
this.View.AddSubview(btnContinue);
I set the height of tableForRows to be GetMaxY() - as I thought this might be the best way to leave it as big as possible. I'm then trying to set the height of the buttons to be ContentSize.Height. Again, I'm sure I've done this wrong, just not sure how to logically do this.
if you want full size view in your app then its like this
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HT [UIScreen mainScreen].bounds.size.height
tableViewForActivities=[[UITableView alloc]init];
tableViewForActivities.frame=CGRectMake(0, 0, SCREEN_WIDTH,SCREEN_HT);
suppose width=50 hight =50
if you want view in centre then by giving width it will adjust automatically within any iOS device
view= [[UIView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH-width)/2, 0, width, width)];
Thank you
you can just put this for
view2 = [[UIView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH-width)/2, CGRectGetMaxY(view.frame), width, width)];
i think this will help you

Table that wouldn't appear in viewDidLoad

I have a static tableview with three rows I am creating programatically. I was creating it (incorrectly) in ViewDidAppear
CGRect fr = CGRectMake(10, 100, 280, 150);
SetUpTableView = [[UITableView alloc] initWithFrame:fr style:UITableViewStylePlain];
SetUpTableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
SetUpTableView.delegate = self;
SetUpTableView.dataSource = self;
[self.view addSubview:SetUpTableView];
it was working fine.
I realized it was in the wrong location so i moved it to viewDidLoad
The table would NOT appear.
I commented out the auto resizing
CGRect fr = CGRectMake(10, 100, 280, 150);
SetUpTableView = [[UITableView alloc] initWithFrame:fr style:UITableViewStylePlain];
// SetUpTableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
SetUpTableView.delegate = self;
SetUpTableView.dataSource = self;
[self.view addSubview:SetUpTableView];
and it now works fine in viewDidLoad.
I understand that I was in the wrong spot AND that this is a static table that doesn't need autoresizing but why would it work in viewDidAppear but not work in viewDidLoad?
It's all about timing.
viewWillAppear is called after the view hierarchy has finished being laid out. This means that whatever voodoo the auto resizing caused will be overridden by layout-related operations performed here.
viewDidLoad is called before the view has finished being laid out - this means that auto-resizing will occur after the code in viewDidLoad is executed.
Hope this clarifies things
In your viewDidLoad, how big is your view?
You have got magic numbers in your code - CGRectMake(10, 100, 280, 150);. If you want the tableview to be a fixed size from the left top right and bottom of your view, work it out, don't assume that you know the size of the view already!
Something like :
CGSize container = self.view.frame.size;
CGRect fr = CGRectMake(10, 100, container.width-60, container.height-100);
Otherwise, you might place your tableview outside the view and the autoresizing mask is just confused!

Creating object programmatically and changing that object's position

I am trying to create a couple of UIImageViews (preferably with a for loop) and then afterwards move them, but I don't know how because I'm having trouble figuring out how to reference them if they will be made programmatically.
So I want something like this:
for (int i = 0; i < 2; i++)
{
UIImageView *iv = [[UIImageView alloc]initWithImage:[UIImage imageNamed: picturo]];
CGRect rect = CGRectMake((i * 50) + 50,30, 25, 25);
[iv setFrame:rect];
iv.tag = i;
[self.view addSubview:iv];
}
(iv with tag of 0).center.y = 80; // <-- How do I do that!!
Obviously this example has no practical use and I could just change y value of 'rect' above to 80, but I want to know how to:
a. Create multiple uiimageviews (or any object for that matter) and be able to identify/reference/manipulate each one individually (I don't know how but I would assume by either naming them uniquely or using tags) and
b. Be able to identify/reference/manipulate an object that was created programmatically.
creating views with tags works the way you have it.
To access those views use the viewWithTag property on a view to identify one of it's subviews:
UIView* subview = [self.view viewWithTag:0];
subview.center = CGPointMake(subview.center.x, 80);
(you cannot write to a view.center's x or y, you have to recreate the whole thing. Likewise with other geometric structs such as CGSize, CGRect)

elegant (i.e., non-hard-coded) way to position `UITextField`, `UITextView`, and `UIButton` relative to each other?

I have the following screen in my app.
Right now the positioning is all hard-coded, and it's not pretty. It's one textview with several \ns in the middle and a textfield and button carefully positioned, experimenting pixel by pixel, and then hard-coded in, which is fine except then if I switch to a 4-inch screen it's useless. Plus it's just ugly.
I've been looking around stackoverflow trying to find answers, and I found some things about creating a CGPoint at a specific UITextPosition, but unfortunately I'm too much a novice to understand the answers.
Is there an elegant way to soft-code these positions relative to each other?
Thanks for your help.
EDIT: Here's the positioning code:
if (!optOut) {
optOut = [[UITextView alloc] initWithFrame:CGRectMake(20, 95, [[UIScreen mainScreen] bounds].size.width - 20, 200);
optOut.backgroundColor=[UIColor clearColor];
optOut.text = #"\n\n\nI hope to update the Haiku app periodically with new haiku, and, if you'll allow me, I'd like permission to include your haiku in future updates. If you're okay with my doing so, please enter your name here so I can give you credit.\n\n\n\nIf you DON'T want your haiku included \nin future updates (which would make \nme sad), check this box.";
}
[self.view addSubview:optOut];
if (!checkboxButton) {
checkboxButton = [UIButton buttonWithType:UIButtonTypeCustom];
checkboxButton.frame = CGRectMake(236, 260, 44, 44);
[self.view addSubview:checkboxButton];
}
[textView resignFirstResponder];
if (!nameField)
{
nameField=[[UITextField alloc] initWithFrame:CGRectMake(40, 223, 240, 30)];
[self.view addSubview:nameField];
}
Instead of placing optOut at (20, 95, [[UIScreen mainScreen] bounds].size.width - 20, 200), I'd like to be able to put it at (say) (20, [[UIScreen mainScreen] bounds].size.height/2-100, [[UIScreen mainScreen] bounds].size.width - 20, 200). But if I do that--if the starting position of optOut moves depending on how tall the screen is--then I have to move nameField and checkBox too, and I don't know how to keep them in the same position relative to optOut.
So first, I would put the second part of that UITextView (after all the returns) into its own object and tack it on to the view by itself. And then the simplest way to go about this with what you have is to ask the elements directly for frame placement, so where you have
checkboxButton.frame = CGRectMake(236, 260, 44, 44);
do something like (and I apologize I if the syntax is a bit off but you can get the idea)
checkboxButton.frame = CGRectMake([optOut center].y + pixelsToMoveOverToWhereYouLikeIt, [optOut center].y + pixelsToMoveDownToWhereYouLikeIt , 44, 44);
And so on for the others. That would make all the view either relative to each other or to one the first textview, depending on which object you reference.
It would be a lot easier to break it apart into different components that you can position individually, and either use constraints to automatically position them or move them individually in code. Also, a UILabel would be better to display the static text, since you don't need the user to be able to edit the text. Something like this:
There are basically two ways you could do this. The first is to use auto-layout. I don't have any experience with auto-layout because it is an iOS 6+ feature, but it would probably be worth learning.
The way I usually do it would be be something like:
view1.frame = CGRectMake(20, 20, 200, 200);
view2.frame = CGRectOffset(view1.frame, 0, 20); // same as view1, offset down 20 points
view3.frame = CGRectMake(CGRectGetMinX(view2.frame), CGRectGetMaxY(view2.frame)+10, 80, 80);
These CGGeometry helper functions are quite useful. There are more obscure CGGeometry functions that are less useful, but can be great in some situations: http://nshipster.com/cggeometry/ For the full list, just check out the CGGeometry documentation
The text field looks indeed ugly there. You want an UITextField of type custom with a nice self styled image as backgound. That way you can postion the text as you want. Do the same with the button of type custom, use 4 different images for the 4 states (unchecked, unchecked-pressed, checked and checked-pressed).

Resources