I'm working on an app in which there is a social feed. I would really like to create a custom view with two tableViews side-by-side. I want to know how you would code this. Is it possible to intercept the scrolling of a table to move the other one at the exact time? Or maybe there is an easier way to achieve this?
I always say the is no limit in programming but the programmer limits. Here's mine.
Thank you for your ideas!
This what I want to do :
Assuming:
Your UITableView objects are called:
tableView1
tableView2
You've hooked their delegates properly
[tableView1 setDelegate:self];
[tableView2 setDelegate:self];
Pre-Requisite:
Declare NSInteger i_check; globally
Implement these scrollView delegate methods:
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
if (scrollView == tableView1) {
i_check = 1;
}
else if (scrollView == tableView2) {
i_check = 2;
}
else { // just incase you have a scrollView that you don't want to track
i_check = 0;
}
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (i_check == 1) {
[tableView2 setContentOffset:scrollView.contentOffset];
}
else if (i_check == 2) {
[tableView1 setContentOffset:scrollView.contentOffset];
}
}
A UITableView internally uses a UIScrollView and since the UITableViewDelegate publicly declares UIScrollViewDelegate, you can access all the scrollView delegate methods by simply setting the tableView object delegate (which you will be doing anyways)
It could be implemented with a UICollectionView.
This should help you a good deal: https://www.cocoacontrols.com/controls/waterfallcollectionview
Related
I have a layout in which I will have 2 UITableViews with custom cells. The second UITableView must be inside the first.
My question is: how to delegate second UITableView?
Can I delegate both to my ViewController? In that case it will use the same methods and I have to find out which UITableView is managed right now.
Or I have to delegate it inside custom UITableViewCell of the first UITableView?
Any recommendations are appreciated.
EDIT: I don't know how to implement solutions here, because I have Storyboard. Inside my current UIViewController I set delegate and dataSource of the first UITableView to my View Controller.
My problem is that I don't know how to set the same properties of the second Table View (which will be inside UITableViewCell). I can not set them to UITableViewCell (IB does not allow that).
Where and how to set then in the IB?
A far better solution would be to abstract the DataSource and Delegate implementations away from your view controller so that they can be personalised per tableview as required (please note that the code is taken from the objc.io article Lighter View Controllers.
E.g.
#implementation ArrayDataSource
- (id)itemAtIndexPath:(NSIndexPath*)indexPath {
return items[(NSUInteger)indexPath.row];
}
- (NSInteger)tableView:(UITableView*)tableView
numberOfRowsInSection:(NSInteger)section {
return items.count;
}
- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
id cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier
forIndexPath:indexPath];
id item = [self itemAtIndexPath:indexPath];
configureCellBlock(cell,item);
return cell;
}
#end
Then you could utilise it as follows:
void (^configureCell)(PhotoCell*, Photo*) = ^(PhotoCell* cell, Photo* photo) {
cell.label.text = photo.name;
};
photosArrayDataSource = [[ArrayDataSource alloc] initWithItems:photos
cellIdentifier:PhotoCellIdentifier
configureCellBlock:configureCell];
self.tableView.dataSource = photosArrayDataSource;
The same process could be followed with the UITableViewDelegate implementations to provide you with a very clean, separated and de-coupled code base. Your requirement for two tableviews will then be intrinsically easier to implement.
My answer is
For identifying two table view data source and delegate method is,better to set tag for the table views.
Set this below coding in your tableview delegates method.
if(tableView.tag==0)
{
}
else
{
}
Also you can vary this by assigning different name to these table view.
if(tableView==FirstTableView)
{
}
else
{
}
You just check table condition for every delegate method
Use this code to register custom cell.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableView == self.yourFirstTable)
{
CustomCell *cell=[tableView dequeueReusableCellWithIdentifier:#"cellModifier"];
// your code
}
else
{
// second table cell code
}
return cell;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(tableView == self.yourFirstTable)
{
// first tableView number of row return
}
else
{
// second table number of row return
}
}
And create prototype cell in TableView
And Set CellReusableId like this way
I have to create a social app, which currently displays only 20 items in a user's news feed. Once they hit the bottom there is a "Load More button this will then extend the stable to the next 20 items.
Its very manual and not very fluid, is there a way to automate this?
The feature is something very similar to the likes of Facebook and Twitter, so I know it is possible but my Googling is only taking me so far as I don't know the right terminology to use for this feature.
Any help would be great!
You can start fetching the next items once the user is near the end of the list.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger maximumNumberOfRows = [tableView numberOfRowsInSection:indexPath.section];
if (indexPath.row >= maximumNumberOfRows - kReloadOffset) {
[self fetchNextItemsFromWebserviceWithOffset:maximumNumberOfRows];
}
In fetchNextItemsFromWebserviceWithOffset you can fetch more news items and update your table view with [self.tableView reloadData].
You can get data when you are near to end using this method or you can also use Mark Gibson's Code.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat offsetY = scrollView.contentOffset.y;
CGFloat contentHeight = scrollView.contentSize.height;
if (offsetY > contentHeight - scrollView.frame.size.height - screensizehere*2)
{
if (!isCalling)
{
isCalling = YES;// when you response data change this bool to NO.
[self getdatainbg];//call your service.
}
}
}
Maybe this will help you.
Use Table view. Load only 20 or whatever amount you require. When you get to the end of the scroll load another 2O. Its very basic and simple. Your cells will get reused again and again and its a never ending, till data is available.
Make your UIViewController class to listen for UIScrollViewDelegate
#interface Yourclass : UIViewController<UIScrollViewDelegate>
/*Your getters & setters, method declarations*/
#end
#pragma mark UIScrollViewDelegate & refresh for auto scroll
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
/*Auto scroll Code.. Raja implemented..*/
if (([scrollView contentOffset].y + scrollView.frame.size.height) == [scrollView contentSize].height) {
[self performSelector:#selector(refreshPage) withObject:nil afterDelay:0.0];
return;
}
}
The Collection View Cell is subclassed in the following way:
I have this layout in a collection view. On each button when it is created, I call the following code:
[cell.imageButton addTarget:self action:#selector(galleryImageButtonClicked:event:) forControlEvents:UIControlEventTouchUpOutside];
Which calls this:
-(void)galleryImageButtonClicked:(id)sender event:(id)event
{
if ([sender isKindOfClass:[UIButton class]])
{
NSLog(#"Yay, it's a UIButton.");
SCCollectionViewCell* parentCellOfThisButton = (SCCollectionViewCell*)[sender superview];
if ([parentCellOfThisButton isKindOfClass:[SCCollectionViewCell class]])
{
UICollectionView *parentCollectionView = (UICollectionView* )[parentCellOfThisButton superview];
if ([parentCollectionView isKindOfClass:[UICollectionView class]])
{
NSIndexPath* indexPathOfCell = [parentCollectionView indexPathForCell:parentCellOfThisButton];
} else {
NSLog(#"Not a UIcollectionClass");
}
} else {
NSLog(#"ERROR! 15268679");
}
}
}
This fails on the line:
if ([parentCellOfThisButton isKindOfClass:[SCCollectionViewCell class]])
Does anyone know why?
To work, the code needs to know where in the cell's view hierarchy the button sits. It might be better to write a method that finds the button's cell more generally, like this:
- (UICollectionViewCell *)cellContainingSubview:(UIView *)view {
while (view && ![view isKindOfClass:[UICollectionViewCell self]]) {
view = [view superview];
}
return view;
}
Then in your button method, there's no need to check if the sender is a button (only the buttons invoke this selector, right?). Get the containing cell like this:
SCCollectionViewCell* parentCellOfThisButton = (SCCollectionViewCell*)[self cellContainingSubview:sender];
Note that the cast is only okay if you know that only SCCollectionViewCells contain the buttons that use this method.
It fails because the internal implementation of UICollectionViewCell uses a more complex set of views than described in the class's interface.
Instead of having your button try to figure out who called it and why, rewrite your code so the button is told what to do. For example, you could specify a different selector depending on what this particular button should be doing.
how would I access this code for determining which tableView is being used in a non tableView method?
I know how to use it in the tableView:numberOfRowsInSection: method but how would I access it in a method I make?
do I use UITableView instead of tableView?
-(void)myMethod {
if ([tableView isEqual:self.tableViewNode])
{
}
if ([tableView isEqual:self.tableViewCities])
{
}
}
I'm looking to see if a tableView is scrollViewDidEndDecelerating: and then perform an action.
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
// NSLog(#"scrollViewDidEndDecelerating");
if ([UITableView isEqual:self.tableViewNode])
{
float endScrolling = scrollView.contentOffset.y + scrollView.frame.size.height;
if (endScrolling >= scrollView.contentSize.height)
{
index ++;
[self getFeed:index];
}
}
if ([UITableView isEqual:self.tableViewCities])
{
}
}
Inside a UIScrollViewDelegate method, you can compare the scrollView argument to the table view properties.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (self.firstTableView == scrollView) {
// respond to firstTableView scrolling
}
else if (self.secondTableView == scrollView) {
// respond to secondTableView scrolling
}
}
If you need to implement methods in your table view's delegate that are called by the delegate methods, but behave differently based on which table view called the calling method, then you should make those methods take a table view parameter and always pass the the table view argument of the delegate methods when you call them. Inside these methods, compare tableView to your properties.
- (void)myMethod:(UITableView *)tableView
{
if (self.firstTableView == tableView) {
// do something for firstTableView
}
else if (self.secondTableView == tableView) {
// etc
}
}
If you needed to call myMethod: from tableView:didSelectRowAtIndexPath: for instance, you'd do something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self myMethod:tableView];
}
I am trying to understand how UITableView accessibility works (in order to add the support to some other libraries that work in a similar way). So I implemented UIAccessibilityContainer Protocol in MyTableView subclass of UITableView.
First of all I need to render the dataSource accessible:
- (id<UITableViewDataSource>)dataSource
{
return (id<UITableViewDataSource>)[self valueForKey:#"_dataSource"];
}
Then I reimplement:
- (NSInteger)indexOfAccessibilityElement:(id)element
{
return [[self indexPathForCell:element] row];
}
- (NSInteger)accessibilityElementCount
{
return [[self dataSource] tableView:self numberOfRowsInSection:0];
}
and accessibility still works as supposed. Last step would be to implement - (id)accessibilityElementAtIndex:(NSInteger)index:
- (id)accessibilityElementAtIndex:(NSInteger)index
{
return [[self dataSource] tableView:self cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]];
}
But apparently adding this method accessibility for the tableview stops working and I get just a VoiceOver "empty list" when navigating (with voiceover) to the tableview. Funny thing cells are returned properly and I get loads of AX ERROR: Could not find my mock parent, most likely I am stale.
I am trying to investigate, I'll post results unless someone comes up with ideas sooner.
Try to Implement those UIAccessibilityProtocal methods inside the UITableviewVell Class. Make the Cell accessible and check.