web-dev-qa-db-ja.com

(動的UITableViewセルから)手動でポップオーバーセグエを実行することは可能ですか?

ユーザーが動的TableViewのセルに触れると、ポップオーバーセグエを実行する必要があります。しかし、私がこのコードでこれをやろうとすると:

- (void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
        [self performSegueWithIdentifier:@"toThePopover" sender:[tableView cellForRowAtIndexPath]];
    //...
} 

エラーが発生するより:

不正な構成

アンカーのないポップオーバーセグエ

これを行う方法はありますか(動的TableViewから手動でポップオーバーセグエを実行するため)?

30
Hlib Dmytriiev

私は今夜​​同じ問題に直面しました、(昔ながらの方法でポップオーバーを提示することを含む)いくつかの回避策があります。

この例では、カスタムセルクラスに格納されているオブジェクトがあります。セルが選択されたら、このような関数を呼び出して、オブジェクトに関する詳細をpopOverViewControllerで開き、テーブル内の対応するセルをポイント(アンカー)します。

_    - (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];
    }
_

このメソッドの問題は、カスタムイニシャライザーを使用するためにポップオーバービューが必要になることが多いことです。これは、ビューをxibではなくストーリーボードで設計し、セルに関連付けられたオブジェクトをその表示に使用するパラメーターとして受け取るカスタムのinitメソッドがある場合に問題になります。また、動的アンカーポイントが必要なため(そして、セルプロトタイプにアンカーできないため)、ポップオーバーセグエ(一見すると)を使用することもできません。だからここに私がやったことがあります:

  1. まず、ビューコントローラービューに非表示の1px X 1px UIButtonを作成します。 (ボタンをビューの任意の場所に移動できるようにするボタン制約を与えることが重要です)
  2. 次に、ビューコントローラーでボタンのアウトレットを作成し(私はpopOverAnchorButtonと呼びます)、非表示のボタンからセグエしたいビューコントローラーにセグエをドラッグします。それをpopOverセグエにします。

これで、「合法的な」アンカーを備えたポップオーバーセグエがあります。ボタンは非表示になっているため、誤ってボタンを押すことはできません。これはアンカーポイントにのみ使用しています。

次のように、関数内でセグエを手動で呼び出すだけです。

_    - (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];
    }
_

そして……出来上がり。今、あなたはセグエの魔法をその偉大さとともに使用しており、あなたの細胞を指すように見える動的なアンカーポイントがあります。 -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)senderで、送信者をセルのクラスにキャストし(送信者のタイプと呼び出されているセグエについて適切なチェックを行う場合)、セグエのdestinationViewControllerにセルのオブジェクトを与えることができます。

これで問題が解決するか、誰かフィードバックや改善点があれば教えてください。

62
johnrechd

セグエではなくコードを使用していますが、タッチしたセルからポップオーバーを表示する代替方法としてこの回答を追加するだけです。それはかなり簡単ですが、iOS 4から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];
}
3
James Toomey

PopoverPresentationControllerを使用した迅速な回答:ストーリーボードを使用して、popoverEditのストーリーボードIDで新しいビューコントローラーを設定します。

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

}
2
Drewster

私はこれを最も簡単な方法で作成しました:

  1. 通常どおり、このポップオーバープレゼンテーションセグエをストーリーボードに作成しますが、ViewController(ボタンではありません)からドラッグします。
  2. アンカービューをテーブルビューとして選択
  3. 次に、テーブルビューのセルのボタンタッチで以下を実行します。

     private func presentCleaningDateDatePicker(from button: UIButton) {
        performSegue(withIdentifier: "Date Picker Popover Segue", sender: button)
    }
    
  4. そして、準備(セグエ)メソッドを実装する

      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
            }
        }
    }
    
0
Michał Ziobro