UICollectionView with UICollectionFlowLayout not displaying cells in the right location - ios

I have a UICollectionView in a test project that I created which does not use Interface Builder. When I run the app the test views that I give to the collection view, via the datasource, are displayed in the the top right corner around (0,0). And I cannot for the life of me figure out why. I have tried adding constraints to the cell's content view. I have also tried messing with the item insets delegate function, but that does not seem to make a difference. Am I missing something?
Here is the code for the test view controller.
#import "TestViewViewController.h"
#interface TestViewViewController () <UICollectionViewDelegateFlowLayout, UICollectionViewDataSource>
#property (strong, nonatomic) UICollectionView *collectionView;
#property (strong, nonatomic) UICollectionViewFlowLayout *flowLayout;
#property (strong, nonatomic) NSMutableArray *testViews;
#end
#implementation TestViewViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)loadView {
self.view = [[UIView alloc] init];
self.view.backgroundColor = [UIColor whiteColor];
self.flowLayout = [[UICollectionViewFlowLayout alloc] init];
self.testViews = [[NSMutableArray alloc] init];
UIView *testView = [[UIView alloc] init];
testView.backgroundColor = [UIColor blueColor];
testView.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *testLabel = [[UILabel alloc] init];
testLabel.translatesAutoresizingMaskIntoConstraints = NO;
testLabel.text = #"I hate collection views.";
[testView addSubview:testLabel];
testView = [[UIView alloc] init];
testView.backgroundColor = [UIColor redColor];
testView.translatesAutoresizingMaskIntoConstraints = NO;
testLabel = [[UILabel alloc] init];
testLabel.translatesAutoresizingMaskIntoConstraints = NO;
testLabel.text = #"I really do.";
[testView addSubview:testLabel];
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.flowLayout];
self.collectionView.translatesAutoresizingMaskIntoConstraints = NO;
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
self.collectionView.backgroundColor = [UIColor grayColor];
[self.view addSubview:self.collectionView];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"MyCell"];
NSDictionary *views = #{#"collectionView": self.collectionView};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[collectionView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[collectionView]|" options:0 metrics:nil views:views]];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
#pragma mark - UICollectionView Datasource
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section {
return self.testViews.count;
}
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView {
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [cv dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
NSLog(#"%i", self.testViews.count);
[cell.contentView addSubview: self.testViews[indexPath.row]];
return cell;
}
#pragma mark – UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
// UIView *statView = self.testViews[indexPath.row];
return CGSizeMake(100.0, 100.0);
}
#end

For openers the CGRectZero macro is the equivalent of CGRectMake(0, 0, 0, 0). It would seem that you'd be in trouble with a definition of the space in which the collection view was to be drawn and the CGRectZero origin of 0,0 would put it in the upper left corner of the view. I tried creating an app with your code - and finally got something to show up when I got the code for loadView to look like this:
- (void) loadView
{
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
self.view.backgroundColor = [UIColor whiteColor];
self.flowLayout = [[UICollectionViewFlowLayout alloc] init];
self.testViews = [[NSMutableArray alloc] init];
UIView* testView = [[UIView alloc] initWithFrame:CGRectMake(0, 50, 320, 80)];
testView.backgroundColor = [UIColor blueColor];
testView.translatesAutoresizingMaskIntoConstraints = NO;
UILabel* testLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 80)];
testLabel.translatesAutoresizingMaskIntoConstraints = NO;
testLabel.text = #"I hate collection views.";
[testView addSubview:testLabel];
[self.testViews addObject:testView];
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 100, 320, 320) collectionViewLayout:self.flowLayout];
self.collectionView.translatesAutoresizingMaskIntoConstraints = NO;
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
self.collectionView.backgroundColor = [UIColor grayColor];
[self.view addSubview:self.collectionView];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"MyCell"];
}
The difference being that objects were created with a frame size - that views were added into views and so on.
My thought is that you'd be better off creating your UICollectionViewin a XIB - setting all the parameters there and also creating a subclass for UICollectionViewCell to be able to do more with the contents of the cells as need be. There's a whole lot more to be done to make this a usable UICollectionView with an arbitrary number of cells, but I have to say, the UICollectionView is not an easy object to deal with - so I sympathize with you as you come up the learning curve.

Related

UISearchBar display issue

The searchbar's right edge is wider than the left, I don't know why? This is not cool.Please help me with this.Thank you very much.
Here's my code:
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, strong) UISearchBar *searchBar;
#property (nonatomic, strong) UISearchDisplayController *strongSearchDisplayController;
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectZero];
self.searchBar.backgroundColor = [UIColor clearColor];
self.searchBar.placeholder = #"搜索";
self.searchBar.delegate = self;
[self.searchBar sizeToFit];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 0.0, SCREENWIDTH, SCREENHEIGHT - NAVIGATIONBARHEIGHT - TABBARHEIGHT ) style:UITableViewStylePlain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
self.tableView.tableHeaderView = self.searchBar;
self.strongSearchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchDisplayController.searchResultsDataSource = self;
self.searchDisplayController.searchResultsDelegate = self;
self.searchDisplayController.delegate = self;
self.searchDisplayController.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
My advice would be to implement your search bars frame this way:
CGRectZero is the equivalent to (0,0,0,0)
Additionally it's best to add the search bar to a view. Like so:
- (void) viewDidLoad:(BOOL)animated {
UIView *searchbarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)]; //This adds a container that will hold the search bar.
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
self.searchBar.delegate = self;
[searchbarView addSubview:self.searchBar];
self.tableView.tableHeaderView = searchbarView; //Inserts UIView into the header of self.tableView
}
You can make following:
Add top offset to your table that is equal to searchBar height:
self.tableView.contentInset = UIEdgeInsetsMake(searchController.searchBar.frame.height, 0, 0, 0);
Add your searchBar to the tableView directly, not to the tableHeaderView:
// remove this
self.tableView.tableHeaderView = self.searchBar;
// insert this
[self.tableView addSubview:self.searchBar];
Please be sure that searchBar rect has correct origin (0, 0)
Note: It will fix your problem, but searchBar's behaviour will be a bit different from original: search bar will be visible by default, there will be no auto-hide of search bar when it's half-closed, etc.

Changing Only Part of a Custom UITableViewCell Selected Background Color

I have a custom cell that I am controlling the color of when it is selected, ie the example code below:
UIView *selectedBackground = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 600)];
[selectedBackground setBackgroundColor:[UIColor selectedCellColor]];
self.selectedBackgroundView = selectedBackground;
This works, however I would only like to have part of the cell change colors when selected. My custom cell is broken down into many different subviews, and I have it sectioned out where I would be able to define the specific view that I would like to change colors for.
How can I control the selectedBackgroundView, or use a different method, to have the background color change encompass a single subview in my cell?
Ya you are in the rite way,by subclassing the UITableView cell
hear is the sample code that you may find the answer for your question :)
//in subclassed cell class
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.frame = CGRectMake(0, 0, 334, 250);
UILabel *aLabel1= [[UILabel alloc]init];
UILabel *aLabel2 = [[UILabel alloc]init];
self.label1 = aLabel1;
self.label2 = aLabel2;
self.label1.text = #"Happy";
self.label2.text = #"coding";
UIImageView *bg1 = [[UIImageView alloc]init];
bg1.tag = 100;
UIImageView *bg2 = [[UIImageView alloc]init];
bg2.tag = 200;
[self addSubview:bg1]; // you must add your background views first
[self addSubview:bg2];
[self addSubview:label1];//then other views
[self addSubview:label2];
[aLabel1 release];
[aLabel2 release];
[bg1 release];
[bg2 release];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
// Configure the view for the selected state
// hear only you can manage your background views, simply i am adding 2 imageviews by setting different colors
[super setSelected:selected animated:animated];
self.backgroundColor = [UIColor greenColor];
if(selected)
{
self.label1.backgroundColor = [UIColor redColor];
self.label2.backgroundColor = [UIColor brownColor];
UIImageView *bg1 = (UIImageView *)[self viewWithTag:100];
bg1.frame = CGRectMake(0, 0,334/2, 250);
bg1.backgroundColor = [UIColor yellowColor];
}
else
{
self.label1.backgroundColor = [UIColor brownColor];
self.label2.backgroundColor = [UIColor redColor];
UIImageView *bg2 =(UIImageView *) [self viewWithTag:200];
bg2.frame = CGRectMake(35, 0, 334/2, 250);
bg2.backgroundColor = [UIColor lightGrayColor];
}
}
-(void)layoutSubviews
{
//i am setting the frame for each views that i hav added
[super layoutSubviews];
self.label1.frame = CGRectMake(10, 10, 60, 35);
self.label2.frame = CGRectMake(65, 10, 60, 35);
}
hope helps u :)
note: i am using "without ARC"

Why are my cells appearing blank in my UITableView?

I have a little bit of an odd structure for my UITableView. Basically, I have ArticleCell objects (subclass of UITableViewCell) that make up the table, and each ArticleCell is comprised of a "front" view and a "back" view. The front view has all the labels and whatnot the user sees, while the back has two icons to the left and right. This two view idea is so the user can slide the top view to the right or left to quickly select an option (kind of like in Reeder).
I've implemented this slightly in the storyboard, but mostly in code. The only thing I did in the storyboard was have the layout of the UITableViewController done, and I named the identifier for the prototype cell (identifier: "ArticleCell").
Other than the storyboard, as I said, everything's done in code. I get the cell's information from Core Data, and construct the cell by setting the article to the cell's article property, which then sets that article to CellFront UIView's article property. Because there's two kinds of cell layouts depending on the type of article the cell holds, in CellFront it checks when kind of cell it is (a property called isUserAddedText) and creates the layout accordingly.
But as I said, nothing's showing up when the app loads, all the cells load and I can tap them to go to their content, but the cells themselves are blank.
The relevant code is as follows:
Cell Data Source:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ArticleInfo *articleInfo = [self.fetchedResultsController objectAtIndexPath:indexPath];
static NSString *CellIdentifier = #"ArticleCell";
ArticleCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[ArticleCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.article = articleInfo;
return cell;
}
In ArticleCell.m, I overrode article's set method so when the data source method above calls it, it could set the view's article property as well.
- (void)setArticle:(ArticleInfo *)article {
_article = article;
self.cellFront.article = article;
}
I also created the CellFront and CellBack UIViews in the ArticleCell.m file:
- (void)awakeFromNib {
[super awakeFromNib];
self.cellBack = [[CellBack alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 80)];
[self.contentView addSubview:self.cellBack];
self.cellFront = [[CellFront alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 80)];
[self.contentView addSubview:self.cellFront];
}
CellFront.m then calls the following method inside its initWithFrame: method, which sets up the labels depending on the kind of article and adds them to the subview.
- (void)addControlsToView {
if ([self.article.isUserAddedText isEqualToNumber:#YES]) {
UILabel *preview = [[UILabel alloc] initWithFrame:CGRectMake(20, 5, 280, 70)];
preview.text = self.article.preview;
preview.numberOfLines = 4;
preview.font = [UIFont systemFontOfSize:16.0f];
preview.textColor = [UIColor blackColor];
preview.backgroundColor = [UIColor clearColor];
[self addSubview:preview];
}
else {
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 280, 20)];
title.text = self.article.title;
title.font = [UIFont boldSystemFontOfSize:18.0f];
title.textColor = [UIColor blackColor];
title.backgroundColor = [UIColor clearColor];
[self addSubview:title];
UILabel *URL = [[UILabel alloc] initWithFrame:CGRectMake(20, 35, 280, 20)];
URL.text = self.article.url;
URL.font = [UIFont systemFontOfSize:16.0f];
URL.textColor = [UIColor blackColor];
URL.backgroundColor = [UIColor clearColor];
[self addSubview:URL];
UILabel *preview = [[UILabel alloc] initWithFrame:CGRectMake(20, 60, 280, 40)];
preview.text = self.article.preview;
preview.numberOfLines = 2;
preview.font = [UIFont systemFontOfSize:16.0f];
preview.textColor = [UIColor grayColor];
preview.backgroundColor = [UIColor clearColor];
[self addSubview:preview];
}
}
That's everything I thought would be relevant to include. Why exactly are all the cells showing up blank?
If you are not using storyboard or NIB's to define your views, awakeFromNib: will never be called.
Here is some documentation
You should try overriding initWithStyle:reuseIdentifier: instead of awakeFromNib:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self != nil) {
// DO STUFF
}
return self;
}
If you are trying to use a storyboard then you are dequeueing the cells incorrectly, replace:
ArticleCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[ArticleCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
With:
ArticleCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
This method will initialize a new cell from the storyboard if there is not one in the queue. The method you were using won't. This means that cell will equal nil sometimes, then you initialize a new cell with the initWithStyle:reuseIdentifier: method, which will not call the awakeFromNib because you are not decoding it from the NIB.
Here is a link to the documentation for this method.
Additional Information
You will also not see the data in the cell because you are setting the label text values in the same block of code that you using to initialize the views. Basically, you need to do:
...
preview.text = self.article.preview;
...
...this part of the addControlsToView method every time the cell is reused, and the initialization of the UILabel only once. I would move the above code into a setter for the article property on CellFront. For example, first declare some properties for the labels
#property (nonatomic, strong) UILabel *preview1Label;
#property (nonatomic, strong) UILabel *titleLabel;
#property (nonatomic, strong) UILabel *URLLabel;
#property (nonatomic, strong) UILabel *preview2Label;
Then something like this to initialize the controls
- (void)initControls {
self.preview1 = [[UILabel alloc] initWithFrame:CGRectMake(20, 5, 280, 70)];
self.preview1.text = self.article.preview;
self.preview1.numberOfLines = 4;
self.preview1.font = [UIFont systemFontOfSize:16.0f];
self.preview1.textColor = [UIColor blackColor];
self.preview1.backgroundColor = [UIColor clearColor];
[self addSubview:self.preview1];
self.title = [[UILabel alloc] initWithFrame:CGRectMake(20, 10, 280, 20)];
self.title.text = self.article.title;
self.title.font = [UIFont boldSystemFontOfSize:18.0f];
self.title.textColor = [UIColor blackColor];
self.title.backgroundColor = [UIColor clearColor];
[self addSubview:self.title];
self.URL = [[UILabel alloc] initWithFrame:CGRectMake(20, 35, 280, 20)];
self.URL.text = self.article.url;
self.URL.font = [UIFont systemFontOfSize:16.0f];
self.URL.textColor = [UIColor blackColor];
self.URL.backgroundColor = [UIColor clearColor];
[self addSubview:self.URL];
self.preview2 = [[UILabel alloc] initWithFrame:CGRectMake(20, 60, 280, 40)];
self.preview2.text = self.article.preview;
self.preview2.numberOfLines = 2;
self.preview2.font = [UIFont systemFontOfSize:16.0f];
self.preview2.textColor = [UIColor grayColor];
self.preview2.backgroundColor = [UIColor clearColor];
[self addSubview:self.preview2];
}
Then something like this to set the controls, likely from the setter of the article property.
- (void)setControls {
if ([self.article.isUserAddedText isEqualToNumber:#YES]) {
self.preview1.hidden = NO;
self.preview1.text = self.article.preview;
self.title.hidden = YES;
self.title.text = nil;
self.URL.hidden = YES;
self.URL.text = nil;
self.preview2.hidden = YES;
self.preview2.text = nil;
}
else {
self.preview1.hidden = YES;
self.preview1.text = nil;
self.title.hidden = NO;
self.title.text = self.article.title;
self.URL.hidden = NO;
self.URL.text = self.article.url;
self.preview2.hidden = NO;
self.preview2.text = self.article.preview;
}
}

UIProgressView work not correctly when setFrame in UICollectionViewCell

I create a UIProgressView inside UICollectionViewCell, I try to setFrame for UIProgressView to change position in UICollectionViewCell but when do that, some cells not display progressView.
When I delete setFrame, It's OK but default width at the top of UICollectionViewCell
What's the problem?How to change UIProgressView size, origin? Please help!
//Cell:UICollectionViewCell
//Cell.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//ProgressView
self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar];
[self.progressView setFrame:progressViewFrame];//Some cells not display progressView
[self.progressView addSubview:self.downloadBar];
}
return self;
}
I have modified you code. Now, progress view is working properly. All cells are showing the progress view. Also, width & position of the cell can be modified, if you change the frame of self.downloadBin the below code
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self.contentView setBackgroundColor:[UIColor underPageBackgroundColor]];
//cellImage
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 0, 57, 57)];
[self.imageView setBackgroundColor:[UIColor clearColor]];
[self.contentView addSubview:self.imageView];
//ProgressView
self.downloadBar = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar];
[self.downloadBar setFrame:CGRectMake(0, 10, 300, 10)];
[self.contentView addSubview:self.downloadBar];
[self.downloadBar setHidden:YES];
self.receivedData = [[NSMutableData alloc] init];
}
return self;
}
I have modified the code of cell.m from the github url which you have provided.

Trying to construct a tableview with a navigation bar at top

Here's the code I used. What am I missing?
- (void)loadView
{
CGSize screen_size = [[UIScreen mainScreen] bounds].size;
CGFloat navBarHeight = 40;
UINavigationBar *nav = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, screen_size.width, navBarHeight)];
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, navBarHeight, screen_size.width, screen_size.height - navBarHeight) style:UITableViewStylePlain];
table.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
table.delegate = self;
table.dataSource = self;
table.editing = YES;
[table reloadData];
[self.view addSubview:nav];
[self.view addSubview:table];
[nav release];
[table release];
}
Instead of a nav bar with a table underneath, I get a black screen under the status bar.
You need to create a containing view in your loadView method and set it as the view on your view controller:
- (void)loadView {
CGSize screen_size = [[UIScreen mainScreen] bounds].size;
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0,0,screen_size.width,screen_size.height)];
self.view = myView;
CGFloat navBarHeight = 40;
UINavigationBar *nav = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, screen_size.width, navBarHeight)];
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, navBarHeight, screen_size.width, screen_size.height - navBarHeight) style:UITableViewStylePlain];
table.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
table.delegate = self;
table.dataSource = self;
table.editing = YES;
[table reloadData];
[self.view addSubview:nav];
[self.view addSubview:table];
[nav release];
[table release];
[myView release];
}
Or alternately, if you have a nib file associated with your view controller then you should be using the viewDidLoad method instead of loadView.

Resources