Ios-8 and Later - Uitableview Inside an Uialertcontroller

iOS-8 and later - UITableView inside an UIAlertController

Courtesy of StackOverflow users I was able to do this task.

Here is my code:

UIViewController *controller = [[UIViewController alloc]init];
UITableView *alertTableView;
CGRect rect;
if (array.count < 4) {
rect = CGRectMake(0, 0, 272, 100);
[controller setPreferredContentSize:rect.size];

}
else if (array.count < 6){
rect = CGRectMake(0, 0, 272, 150);
[controller setPreferredContentSize:rect.size];
}
else if (array.count < 8){
rect = CGRectMake(0, 0, 272, 200);
[controller setPreferredContentSize:rect.size];

}
else {
rect = CGRectMake(0, 0, 272, 250);
[controller setPreferredContentSize:rect.size];
}

alertTableView = [[UITableView alloc]initWithFrame:rect];
alertTableView.delegate = self;
alertTableView.dataSource = self;
alertTableView.tableFooterView = [[UIView alloc]initWithFrame:CGRectZero];
[alertTableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
[alertTableView setTag:kAlertTableViewTag];
[controller.view addSubview:alertTableView];
[controller.view bringSubviewToFront:alertTableView];
[controller.view setUserInteractionEnabled:YES];
[alertTableView setUserInteractionEnabled:YES];
[alertTableView setAllowsSelection:YES];
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" preferredStyle:UIAlertControllerStyleAlert];
[alertController setValue:controller forKey:@"contentViewController"];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {

}];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];

Checkout the snapshot here ;)

Customize UIAlertController in iOS 8 to include standard elements like UITableView

I ran into the same issue right now. I looked at the private header for UIAlertController (https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIAlertController.h) and found a promising property: contentViewController

And it turned out to be exactly the same as accessoryView used to be for UIAlertView, the difference being that you need to assign a UIViewController to this property rather than a UIView.

UIViewController *v = [[UIViewController alloc] init];
v.view.backgroundColor = [UIColor redColor];

[alertController setValue:v forKey:@"contentViewController"];

That piece of code will show a red view on the alert view! Happy UIAlertController customizing ;)

PS. It is a private property but using KVC there shouldn't be a problem App Store wise, I think.

Edit:

Some people complained that this isn't very safe. It's not a public API, so yes, Apple could change it in any release, causing this method to fail.

To make sure your entire app doesn't crash if that happens you could wrap the KVC call in a try block. If the property changes your controller won't show the content view, but it also won't crash:

@try {
[alertController setValue:v forKey:@"contentViewController"];
}
@catch(NSException *exception) {
NSLog(@"Failed setting content view controller: %@", exception);
}

Using this method in production can be risky, and I don't recommend it for important alerts.

Calling UIAlertController inside a UITableViewCell

You can try to use delegate

protocol AlertShower{
func showAlert(TableCustomCell)
}

class TableCustomCell: UITableViewCell {
var delegate: AlertShower?

@IBAction func showClicked(_ sender: UIButton) {
self.delegate?.alertShower(sender:self)
}
}

in the VC

class viewController: UIViewController, AlertShower {

override func viewDidLoad() {
super.viewDidLoad()

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = areaSettTable.dequeueReusableCell(withIdentifier:CellIdentifier1) as! TableCustomCell

cell.delegate = self

return cell
}

func showAlert(sender:TableCustomCell) {

// show alert here

}
}

How to add UITableview in UIAlertController in iOS8?

Please try below code with custom view and animations

Test.h

#import <UIKit/UIKit.h>

@interface Test : UIView <UITableViewDataSource,UITableViewDelegate>
{
UITableView *table;
}

- (id)initWithFrame:(CGRect)frame Array:(NSArray *)ArrayValue;
- (void)showInView:(UIView *)aView animated:(BOOL)animated;
- (void)fadeOut;

@end

Test.m

- (id)initWithFrame:(CGRect)frame Array:(NSArray *)ArrayValue
{
if (self = [super initWithFrame:frame])
{
aryType = ArrayValue;
table = [[UITableView alloc] initWithFrame:CGRectMake(15, 0, 320, 380) style:UITableViewStylePlain];
table.dataSource = self;
table.delegate = self;
[table setSeparatorInset:UIEdgeInsetsZero];
table.showsVerticalScrollIndicator = YES;
[self addSubview:table];
}
return self;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return aryType.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
}
cell.textLabel.text = [aryType objectAtIndex:(indexPath.row)];
cell.textLabel.font = [UIFont fontWithName:@"Avenir Next" size:16];
return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(@"select");
}

- (void)fadeIn
{
self.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.alpha = 0;
[UIView animateWithDuration:.35 animations:^{
self.alpha = 1;
self.transform = CGAffineTransformMakeScale(1, 1);
}];
}

- (void)fadeOut
{
[UIView animateWithDuration:.35 animations:^{
self.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.alpha = 0.0;
} completion:^(BOOL finished) {
if (finished) {
[self removeFromSuperview];
}
}];
}

- (void)showInView:(UIView *)aView animated:(BOOL)animated
{
[aView addSubview:self];
if (animated)
{
[self fadeIn];
}
}

At last from your viewcontroller call this view as per below code

Viewcontroller.m

- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *aryType = [[NSArray alloc] initWithObjects:@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10", nil];
[self showPopUpWithTitle:@"Title" arrOptions:aryType xy:CGPointMake(16, 150) size:CGSizeMake(287, 134)];
}

- (void)showPopUpWithTitle:(NSString *)popupTitle arrOptions:(NSArray *)arrOptions xy:(CGPoint)point size:(CGSize)size
{
testView = [[Test alloc] initWithFrame:CGRectMake(15, point.y, size.width, 200.0) Array:arrOptions];
[testView showInView:self.view animated:YES];
}

iOS - UITableViewCell, UIAlertController

What you are designing for implementing this procedure is not correct. What you can do

  1. Make a custom cell
  2. Add a button in custom cell
  3. Add action in that button in CellForRowAtIndexPath
  4. Handle action from ViewController where you added tableView.

I made a whole project for you.Just to let you know. if you want to add customCell in tableView you need to register it like this in viewDidLoad.
i have done is in ViewController.swift file. check out my project.

let nib = UINib.init(nibName:String(describing: sampleTableViewCell.self) , bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "chatCell")

Then check cellForRowAtIndexPath function:

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCell(withIdentifier: "chatCell", for: indexPath) as! sampleTableViewCell

cell.clickMeBtn.tag = indexPath.row
cell.clickMeBtn.addTarget(self, action: #selector(onButtonPressed(sender :)), for: .touchUpInside)
return cell

}

Button press function:

func onButtonPressed(sender:UIButton) {
let alert = UIAlertController.init(title:"Cell index is"+String(sender.tag), message: nil, preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction.init(title: "ok", style: UIAlertActionStyle.default) { (UIAlertAction) in

}

alert.addAction(okAction)
self.present(alert, animated: true, completion: nil)

}

Check only three files:

Github link

  1. ViewController.swift

  2. sampleTableViewCell.swift

  3. sampleTableViewCell.xib**

Here is the output:

Sample Image

Show an UIAlertController from a button on an UITableViewCell

It crashed because of this line

shareAlert.presentViewController(shareAlert, animated: true, completion: nil)

A controller cannot present itself, so

Replace

shareAlert.presentViewController(shareAlert, ...) 

by

yourCurrentViewController.presentViewController(shareAlert, ...)

And you should not use UIAlertView because it was deprecated in iOS 9 and maybe obsoleted in the next iOS, so use UIAlertController and you don't have to change it in near future

Presenting UIAlertController from UITableViewCell

You can use this extension to find the viewController that present the cell

extension UIView {
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder!.nextResponder()
if parentResponder is UIViewController {
return parentResponder as! UIViewController!
}
}
return nil
}
}

Or use rootViewController to Present:

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(refreshAlert, animated: true, completion: nil)

Swift 4.2 Update

extension UIView {
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder!.next
if parentResponder is UIViewController {
return parentResponder as? UIViewController
}
}
return nil
}
}

Or use rootViewController to Present:

UIApplication.shared.keyWindow?.rootViewController?.present(alertVC, animated: true, completion: nil)


Related Topics



Leave a reply



Submit