I have a UITableView that covers the whole screen, with a lot of cells.
On the view that holds the UITableView I want to display an UIImage at the top right corner.
This UIImage (or UIImageView) is fixed on the UIView - it is not part of the tableView (in the z order it is over the tableView).
It is possible to let the UITableView float around this image, even when scrolling?
Below an image of my desired structure. Imagine that they are more cells even under der image. The cells (or UILabels) that are covered by the image should be truncated (or do a line break).
Is this possible? Currently I have no idea how to do this.
One option is to adjust the trailing space constraint of a label on your custom table view cell based on tableview's scrollview delegate method. You need to check if your cell is in the area of your imageView and then adjust the constraint. You also need to adjust the constraint in your cellForRowAtIndexPath for the initial layout.
Storyboard
ViewController.m
#import "ViewController.h"
#import "MyCell.h"
#interface ViewController () <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#end
#implementation ViewController
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:#"MyCell" forIndexPath:indexPath];
// Configure the cell...
cell.myLabel.text = #"Lorem ipsum dolor sit amet, etc.";
if (indexPath.row >=3 && indexPath.row <= 5) {
cell.trailingSpaceConstraint.constant = 168;
}
return cell;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSUInteger count = 0;
for (MyCell *cell in [self.tableView visibleCells]) {
if (count >= 3 && count <= 6) {
cell.trailingSpaceConstraint.constant = 168.0;
} else {
cell.trailingSpaceConstraint.constant = 20.0;
}
count++;
}
}
#end
MyCell.h
#import <UIKit/UIKit.h>
#interface MyCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *trailingSpaceConstraint;
#end
Output
In this sample you need to use custom ViewController, add tableView and imageView, hook tableView's delegate and datasource and outlet. You also need to add custom subclass of UITableViewCell (MyCell) and hook outlets of the cell's label and the trailing space constraint.
The check at scrollViewDidScroll for rows is quick and dirty. Probably a better solution might be to check which cells are touching the imageView rect in indexPathsForRowsInRect.
Related
I need some help with a uicollectionview that I've been trying to implement in Objective-C/xcode: I am unable to have the cells appear/populate the collectionview (CV).
Currently I am using the interface builder, and a custom class for cells.
The CV is to be a wide strip that is a single row of square image cells, that can be scrolled/swept through horizontally.
My attempts at implementation result in the wide strip but it never populates with cells.
I have explored other stackoverflow threads similar to this issue, where they discuss the subclassing of cell but I was unable to make it work. Have also tried programmatic implementation and had the same issue. Would really appreciate any insight as I have been stuck at this point for days. Below the code I am using, are screenshots of interface builder showing different settings... some I know are useful to include and I apologize if I have shared anything useless.
from ViewController.h
#interface ViewController : UIViewController <UICollectionViewDelegate,UICollectionViewDataSource>
#property (weak, nonatomic) NSMutableArray *medCollectionCells;
from ViewController.m
#import "CoolCell.h"
#property (weak, nonatomic) IBOutlet UICollectionView *medCollection;
- (void)viewDidLoad
{
_medCollectionCells = [NSMutableArray arrayWithObjects:#"1st cell",#"2nd cell",#"3rd cell",#"4th cell",#"5th cell",#"6th cell",#"7th cell",#"8th cell",#"5th cell", nil];
self.medCollection.delegate = self;
self.medCollection.dataSource = self;
}
// collection view delegate methods
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [_medCollectionCells count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CoolCell *cell = (CoolCell *)[_medCollection dequeueReusableCellWithReuseIdentifier:#"MyCustomCell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor blackColor];
return cell;
}
CoolCell.h:
#import <UIKit/UIKit.h>
#interface CoolCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UILabel *customLabel;
#property (weak, nonatomic) IBOutlet UIImageView *customImage;
#end
CoolCell.m:
#import "CoolCell.h"
#implementation CoolCell
#end
Screen Shots
Storyboard layout
Collection View Settings 1
Collection View Settings 2
Cell Settings 1
Cell Settings 2
Interface Builder Outlets
Grateful for any assistance/insight. Thank you.
Seems like the delegate and dataSource properties are connected to a View object in Interface Builder. Maybe remove that since you are setting those properties in code.
I can't figure out why my UILabels in my custom TableViewCell are nil in CellForRowAtIndexPath. I used the same method as I did for a previous TableView in another view Controller. Here's what I already checked:
Cell Style is Custom
Cell has a unique identifier "profilecell"
Cell's class is of the desired custom type
data source and delegated are connected to the View Controller
Each of the 5 buttons/labels is connected to its respective property in the custom class
Dynamic Prototypes is selected
I am able to change the background color of the cell and populate the textLabel.text -- it's just my UILabels that aren't filled.
Here is CellForRowAtIndexPath. It's the exact same method as my other TableVC, which works. Also, I don't need to actually reuse this custom cell, should I be using a different method?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifierProfile = #"profilecell";
ProfileSection0TableViewCell *profilecell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierProfile];
if (profilecell == nil) {
profilecell = [[ProfileSection0TableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifierProfile];
}
if (indexPath.section == 0) {
[profilecell setBackgroundColor:[UIColor colorWithRed:54/255.0f green:61/255.0f blue:147/255.0f alpha:1.0f]];
if (indexPath.row == 0) {
profilecell.labelName.text = _userProfile.fullName;
NSString *test = [NSString stringWithFormat:#"%#", profilecell.labelName.text];
NSLog(#"text %#", test); //shows that label is (null)
profilecell.labelName.textColor = [UIColor whiteColor];
//profilecell.labelSpecialty.text = _userProfile.specialty;
//profilecell.labelSpecialty.textColor = [UIColor whiteColor];
}
}
return profilecell;
}
Thanks so much in advance.
.h file:
#interface ProfileSection0TableViewCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel* labelName;
#property (nonatomic, weak) IBOutlet UILabel* labelSpecialty;
#property (nonatomic, weak ) IBOutlet UILabel* labelCurrentRole;
#property (nonatomic, weak) IBOutlet UILabel* labelPosition;
#property (nonatomic, weak) IBOutlet UIButton* facePicture;
#end
.m file:
#implementation ProfileSection0TableViewCell
#synthesize labelName, labelSpecialty, labelPosition, facePicture, labelCurrentRole;
#end
EDIT:
It looks like ProfileSection0TableViewCell is allocated properly, but the member vars inside the cell are nil. And in outlets, here are the connections:
facePicture - Button
labelName- UILabel "person"
labelPosition - UILabel "position"
List item - UILabel "specialty"
labelCurrentRole - UILabel titled school
Either _userProfile.fullName is nil or profilecell.labelName is nil
If you made the cell in interface builder, did you hook up the outlet to labelName correctly?
I'm working on a custom layout collectionView which has quilt look and each section has a footer. Two buttons are inside footer and each button has a segue to another view(I set segues using IB).
Footer has its own indexPath which was assigned in a UICollectionViewFlowLayout class(Where I made a custom layout). The indexPath of footer is like this - {section - row} {0-0} {1-0} {2-0}....
I want to keep this indexPath information to use at the another view which is linked to two buttons.
I tried "convertPoint: toView: ... indexPathForRowAtPoint" way but didn't work. I think it's because the buttons are not belong to collectionViewItem but belong to Footer.
In this situation, what is the best way of passing each footerView's indexPath to segue?
Any solution with code example will be greatly appreciated.
// CollectionView DataSource
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath {
Footer *footerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter
withReuseIdentifier:#"Footer"
forIndexPath:indexPath];
// set button images and labels
[footerview setButton];
// debug code : show current section number
footerview.footerLabel.text = [NSString stringWithFormat:#"Section %li", (long)indexPath.section];
return footerview;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"SeeAllPictures"]) {
// how to pass indextPath?
}
else if([[segue identifier] isEqualToString:#"GoDiary"]) {
// how to pass indextPath?
}
}
Below is header of Footer class
#import <UIKit/UIKit.h>
#interface Footer : UICollectionReusableView
#property (strong, nonatomic) IBOutlet UILabel *footerLabel;
#property (strong, nonatomic) IBOutlet UIButton *seeAllPictures;
#property (strong, nonatomic) IBOutlet UIButton *goDiary;
#property (strong, nonatomic) IBOutlet UIImageView *seeAllPicturesImage;
#property (strong, nonatomic) IBOutlet UILabel *seeAllPicturesLabel;
#property (strong, nonatomic) IBOutlet UIImageView *goDiaryImage;
#property (strong, nonatomic) IBOutlet UILabel *goDiaryLabel;
- (void)setButton;
#end
try the following:
imagine a reusable view with two buttons (leftButton and rightButton). in your reusable view classes .h file add a property for the indexpath:
#property (strong, nonatomic) NSIndexPath *indexPath;
then in your viewcontrollers viewForSupplementaryElementOfKind method:
CustomFooterView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:#"FooterView" forIndexPath:indexPath];
footerView.indexPath = indexPath;
[footerView.leftButton addTarget:self action:#selector(leftButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[footerView.rightButton addTarget:self action:#selector(rightButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
then implement the two methods:
- (void)leftButtonTapped:(UIButton *)sender {
[self performSegueWithIdentifier:#"LeftButtonSegue" sender:sender];
}
- (void)rightButtonTapped:(UIButton *)sender {
[self performSegueWithIdentifier:#"RightButtonSegue" sender:sender];
}
and finally in your viewcontrollers prepareForSegue method:
CustomFooterView *footerView = (CustomFooterView *)((UIButton *)sender).superview;
NSLog(#"perform segue from indexpath %ld, %ld", (long) footerView.indexPath.section, (long) footerView.indexPath.row);
IMPORTANT
the buttons have to be direct childs of the reusable view to make
(CustomFooterView *)((UIButton *)sender).superview
work. and of course you have to connect the segues LeftButtonSegue and RightButtonSegue in storyboard.
I have designed a cell in storyboard, then created a custom UITableViewCell subclass (BasicCell) and assigned it to it. Also set the proper identifiers. I created outlets of the custom cell in that class. Then in my UITableViewController subclass (where I have two types of prototype cells), the cells content won't show up. What am I doing wrong?
BasicCell.h
#interface BasicCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *scorevalue;
#property (strong, nonatomic) IBOutlet UILabel *avgvalue;
#property (strong, nonatomic) IBOutlet UILabel *rankvalue;
#property (strong, nonatomic) IBOutlet UILabel *scorelabel;
#property (strong, nonatomic) IBOutlet UILabel *categorylabel;
#property (strong, nonatomic) IBOutlet UILabel *ranklabel;
#end
TableViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifierBasic = #"basic";
static NSString *CellIdentifierDetailed = #"detailed";
UITableViewCell *cell;
if(indexPath.row==0){
// Create first cell
cell = [[BasicCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifierBasic];
}
else{
// Create all others
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierDetailed forIndexPath:indexPath];
}
// Configure the cell...
switch ([indexPath row])
{
case 0:
{
BasicCell *basicCell = (BasicCell *)cell;
basicCell.scorelabel.text = #"test";
basicCell.categorylabel.text = #"test";
basicCell.ranklabel.text = #"test";
basicCell.scorevalue.text = #"test";
basicCell.avgvalue.text = #"test";
basicCell.rankvalue.text = #"test";
}
}
In your storyboard,
Create two prototype cell.
Change one of your prototype cell's custom class. Set it BasicCell.
Make sure that you set appropriate cell identifier for each type of cell.
Don't alloc init if it's indexPath.row == 0 but dequeue with appropriate identifier.
It should work.
Note: You should declare your IBOutlets as weak not as strong. Cell's view has already strong pointer to them. You don't have to own them.
I create a xib file and add a Collection View Cell. I add the progress bar in header file of cell like the following code.
#import <UIKit/UIKit.h>
#import "MobileVLCKit/VLCMediaThumbnailer.h"
#interface AITFileCell_grid : UICollectionViewCell <VLCMediaThumbnailerDelegate>
#property (strong, nonatomic) IBOutlet UIImageView *fileIcon;
#property (strong, nonatomic) IBOutlet UILabel *fileName;
#property (strong, nonatomic) IBOutlet UILabel *fileSize;
#property (strong, nonatomic) NSURL *filePath ;
+ (NSString *)reuseIdentifier ;
#end
#interface AITFileCell_grid()
{
BOOL fetching ;
#public
UIProgressView *dlProgress;
UILabel *dlProgressLabel;
}
#end
I also create another xib file and add the Collection View for loading Collection View Cell.
I want to selected multiple file and hide the progress bar on each cell by button.
But I can not get the cell when I click the delete button by following code.
- (IBAction) buttonCancel:(id)sender {
if(self.collectionView.indexPathsForSelectedItems > 0){
for(NSIndexPath *indexPath in self.collectionView.indexPathsForSelectedItems){
AITFileCell_grid *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"AITFileCell_grid" forIndexPath:indexPath];
//Hide the progress bar
cell->dlProgressLabel.text = #"0%";
cell->dlProgress.hidden = YES;
cell->dlProgressLabel.hidden = YES;
}
}
[self setEditing:NO animated:YES];
}
I set the breakpoint to the cell->dlProgressLabel.text = #"0%"; , it show the nil in the log...and the progress bar didn't change anything.
But I can set the value to cell->dlProgressLabel.text and set value to cell->dlProgress in NSTimer.
Why the cell define in the UIButton seems not be efficient ?...
Can someone help and teach me how to solve ?
You are dequeuing Cell by doing
AITFileCell_grid *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"AITFileCell_grid" forIndexPath:indexPath];
which could be different from what you have been selected, instead get the selected cell from the collectionView
AITFileCell_grid *cell = [self.collectionView cellForItemAtIndexPath: indexPath]