ios - ¿Es posible realizar una Segue Popover manualmente(desde la celda dinámica UITableView)?
uipopovercontroller (4)
Necesito realizar un segmento de Popover cuando el usuario toca una celda en un TableView dinámico. Pero cuando intento hacer esto con este código:
- (void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:@"toThePopover" sender:[tableView cellForRowAtIndexPath]];
//...
}
que me sale un error:
Configuración ilegal
Popover segue sin ancla
¿Hay alguna manera de hacer esto (para realizar un segmento de popover desde TableView dinámico manualmente)?
Lo he hecho de la manera más sencilla:
- Realice este segmento de presentación de Popover en el guión gráfico como de costumbre, pero arrastre desde ViewController (no el botón)
- Seleccione la vista de anclaje como vista de tabla
Luego, en la vista de tabla, el botón de la celda toca hacer:
private func presentCleaningDateDatePicker(from button: UIButton) { performSegue(withIdentifier: "Date Picker Popover Segue", sender: button) }
e implementar el método de preparación (para segue)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let identifier = segue.identifier { switch identifier { case "Date Picker Popover Segue": if let vc = segue.destination as? DatePickerViewController { if let ppc = vc.popoverPresentationController { ppc.sourceView = sender as! UIButton ppc.sourceRect = (sender as! UIButton).frame ppc.delegate = vc vc.minimumDate = Date() vc.maximumDate = Date().addMonth(n: 3) vc.delegate = self } } default: break } } }
Me enfrenté a este mismo problema esta noche, hay un par de soluciones (incluida la presentación del popover a la antigua).
Para este ejemplo, tengo un objeto que está almacenado en mi clase de celda personalizada. Cuando se selecciona la celda, llamo a una función como esta para abrir detalles en un popOverViewController sobre el objeto, y apunto (ancla) a su celda correspondiente en la tabla.
- (void)openCustomPopOverForIndexPath:(NSIndexPath *)indexPath{
CustomViewController* customView = [[self storyboard] instantiateViewControllerWithIdentifier:@"CustomViewController"];
self.myPopOver = [[UIPopoverController alloc]
initWithContentViewController:customView];
self.myPopOver.delegate = self;
//Get the cell from your table that presents the popover
MyCell *myCell = (MyCell*)[self.tableView cellForRowAtIndexPath:indexPath];
CGRect displayFrom = CGRectMake(myCell.frame.origin.x + myCell.frame.size.width, myCell.center.y + self.tableView.frame.origin.y - self.tableView.contentOffset.y, 1, 1);
[self.myPopOver presentPopoverFromRect:displayFrom
inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}
El problema con este método es que a menudo necesitamos que la vista emergente tenga un inicializador personalizado. Esto es problemático si desea que su vista se diseñe en el guión gráfico en lugar de un xib y tenga un método de inicio personalizado que tome el objeto asociado de sus celdas como un parámetro para usarlo en su visualización. Tampoco puede simplemente usar un segmento de popover (a primera vista) porque necesita un punto de anclaje dinámico (y no puede anclar a un prototipo de celda). Así que aquí está lo que hice:
- Primero, cree un UIButton oculto de 1px X 1px en la vista de los controladores de vista. (importante dar restricciones al botón que permitirán moverlo a cualquier lugar de la vista)
- Luego haga una salida para el botón (yo llamé mío popOverAnchorButton) en su controlador de vista y arrastre un segmento desde el botón oculto hasta el controlador de vista que desea segue. Haz que sea un pop segue segue.
Ahora tienes una ventana emergente con un ancla ''legal''. El botón está oculto, por lo que nadie puede tocarlo accidentalmente. Sólo está utilizando esto para un punto de anclaje.
Ahora solo llama a tu segue manualmente en tu función como esta.
- (void)openCustomPopOverForIndexPath:(NSIndexPath *)indexPath{
//Get the cell from your table that presents the popover
MyCell *myCell = (MyCell*)[self.tableView cellForRowAtIndexPath:indexPath];
//Make the rect you want the popover to point at.
CGRect displayFrom = CGRectMake(myCell.frame.origin.x + myCell.frame.size.width, myCell.center.y + self.tableView.frame.origin.y - self.tableView.contentOffset.y, 1, 1);
//Now move your anchor button to this location (again, make sure you made your constraints allow this)
self.popOverAnchorButton.frame = displayFrom;
[self performSegueWithIdentifier:@"CustomPopoverSegue" sender:myCell];
}
Y voilá. Ahora estás usando la magia de los segmentos con toda su grandeza y tienes un punto de anclaje dinámico que parece apuntar a tu celda. ahora en -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
, simplemente puede -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
el remitente a la clase de su celda (dado que realiza las comprobaciones adecuadas del tipo de remitente y a qué segue se está llamando) y proporcione la segue destinationViewController del objeto de la celda.
Déjeme saber si esto ayuda, o si alguien tiene algún comentario o mejora.
Respuesta rápida mediante popoverPresentationController: mediante el uso del guión gráfico, configure el nuevo controlador de vista con una ID del guión gráfico de popoverEdit.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let fromRect:CGRect = self.tableView.rectForRowAtIndexPath(indexPath)
let popoverVC = storyboard?.instantiateViewControllerWithIdentifier("popoverEdit") as! UIViewController
popoverVC.modalPresentationStyle = .Popover
presentViewController(popoverVC, animated: true, completion: nil)
let popoverController = popoverVC.popoverPresentationController
popoverController!.sourceView = self.view
popoverController!.sourceRect = fromRect
popoverController!.permittedArrowDirections = .Any
}
Simplemente agregue esta respuesta como una forma alternativa de presentar una ventana emergente desde una celda tocada, aunque usa código en lugar de un segmento. Sin embargo, es bastante simple y me ha funcionado desde iOS 4 hasta iOS 7:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
//get the data of the row they clicked from the array
Url* clickedRec = [self.resultsArray objectAtIndex:indexPath.row];
//hide the popover in case it was already opened from a previous touch.
if (self.addNewPopover.popoverVisible) {
[self.addNewPopover dismissPopoverAnimated:YES];
return;
}
//instantiate a view controller from the storyboard
AddUrlViewController *viewControllerForPopover =
[self.storyboard instantiateViewControllerWithIdentifier:@"addUrlPopup"];
//set myself as the delegate so I can respond to the cancel and save touches.
viewControllerForPopover.delegate=self;
//Tell the view controller that this is a record edit, not an add
viewControllerForPopover.addOrEdit = @"Edit";
//Pass the record data to the view controller so it can fill in the controls
viewControllerForPopover.existingUrlRecord = clickedRec;
UIPopoverController *popController = [[UIPopoverController alloc]
initWithContentViewController:viewControllerForPopover];
//keep a reference to the popover since I''m its delegate
self.addNewPopover = popController;
//Get the cell that was clicked in the table. The popover''s arrow will point to this cell since it was the one that was touched.
UITableViewCell *clickedCell = [self.tableView cellForRowAtIndexPath:indexPath];
//present the popover from this cell''s frame.
[self.addNewPopover presentPopoverFromRect:clickedCell.frame inView:self.myTableView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}