0

インターフェイス ビルダーを使用してカスタム セルを作成しました。2 つのラベルと 1 つの UIButton があります。cellForRowAtIndexPath または willDisplayCell 内の各ラベルのテキストを問題なく設定できます。ただし、UIButton のイメージを設定すると、いずれかの場所で問題が発生します。問題は、私が完全には理解していないセルの再利用/キャッシュに関連していると思います。

主に willDisplayCell を使用する現在のコードを次に示しますが、ほとんどのコードを cellForRowAtIndexPath に移動しようとしても同じ結果になりました。

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIButton *check = (UIButton*) [cell.contentView viewWithTag:1];
    UIButton *check2 = (UIButton*) [cell.selectedBackgroundView viewWithTag:1];
    UILabel *from = (UILabel*) [cell.contentView viewWithTag:2];
    UILabel *subject = (UILabel*) [cell.contentView viewWithTag:3];

    // Configure the cell...
    Message *rec = (Message*) Records[indexPath.row];
    if(rec.Checked)
        check.imageView.image = [UIImage imageNamed:@"Checkedbox.png"];
    else
        check.imageView.image = [UIImage imageNamed:@"Checkbox.png"];
    check2.imageView.image = check.imageView.image;
    from.text = rec.From;
    subject.text = rec.Subject;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    return cell;
}

上記のコードでは、check2 は nil です。私はそれなしでも試しましたが、最近、修正の試みとしてそれを追加しました。

私は基本的にメッセージ リスト (受信トレイ) を作成しており、GMail のようなチェックボックスが必要です。私が持っているチェックボックスボタンのクリックイベントで:

- (IBAction)CheckClicked:(id)sender
{
    UITableViewCell *cell = (UITableViewCell*) [[sender superview] superview];
    NSIndexPath *indexPath = [[self tableView] indexPathForCell:cell];
    Message *rec = (Message*) Records[indexPath.row];
    rec.Checked = !rec.Checked;
    [cell setNeedsLayout];
    [cell.contentView setNeedsLayout];
    [cell setNeedsDisplay];
    [cell.contentView setNeedsDisplay];
    [self.tableView reloadData];
}

上記の setNeedsLayout と setNeedsDisplay の呼び出しはすべて冗長であることを知っています。ほとんどの場合、機能しなかったことを示すためにそれらを使用しています。ほとんどの例では、セルの setNeedsLayout が機能するはずであると言われていますが、reloadData のみが少なくとも各セルを再描画/更新します。

クリックするとチェックボックスが正しく変更されますが、1 つのセルにチェックマークを付けてからクリックしてセルを強調表示すると、ビューが画面外にスクロールしてから戻るまでチェックボックスがオフになります。問題は、選択されたものと選択されていないものとで異なるビューがあることに関連していると思いましたが、それ以上に何を確認すればよいかわかりません。

編集:ほとんどのチュートリアルはこれに似たコードを使用しているため、ここでも試してみましたが、この使用法では、ブレークポイントを設定して cellForRowAtIndexPath が実行されていることを確認できても、セルがスクロールされて画面に戻るまで画像は変化しません。クリックイベントで reloadData が呼び出された後、各セルに対して再度呼び出され、チェックしたアイテムをチェックするように画像を正しく設定しています:

- (IBAction)CheckClicked:(id)sender
{
    UITableViewCell *cell = (UITableViewCell*) [[sender superview] superview];
    NSIndexPath *indexPath = [[self tableView] indexPathForCell:cell];
    Message *rec = (Message*) Records[indexPath.row];
    rec.Checked = !rec.Checked;
    [self.tableView reloadData];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    // NOTE: In my testing cell is never NULL, so I have no checking here.

    UIButton *check = (UIButton*) [cell.contentView viewWithTag:1];
    UILabel *from = (UILabel*) [cell.contentView viewWithTag:2];
    UILabel *subject = (UILabel*) [cell.contentView viewWithTag:3];

    // Configure the cell...
    Message *rec = (Message*) Records[indexPath.row];
    if(rec.Checked)
        check.imageView.image = [UIImage imageNamed:@"Checkedbox.png"];
    else
        check.imageView.image = [UIImage imageNamed:@"Checkbox.png"];
    from.text = rec.From;
    subject.text = rec.Subject;

    return cell;
}
4

2 に答える 2

1

これが良い答えかどうかはわかりませんが、うまくいっているように見えますし、おそらく Apple が意図した方法です。

別の SO 回答UITableViewCell Reuse and Images Re-renderからアイデアを得ました。ここでは、異なるスタイルごとに複数のプロトタイプを使用していました。

代わりに、IB で 2 つのプロトタイプ セルを作成しました。次に、コードを次のように更新しました。

- (IBAction)CheckClicked:(id)sender
{
    UITableViewCell *cell = (UITableViewCell*) [[sender superview] superview];
    NSIndexPath *indexPath = [[self tableView] indexPathForCell:cell];
    Message *rec = (Message*) Records[indexPath.row];
    rec.Checked = !rec.Checked;
    [self.tableView reloadData];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    Message *rec = (Message*) Records[indexPath.row];

    UITableViewCell *cell;
    if(rec.Checked)
        cell = [tableView dequeueReusableCellWithIdentifier:@"CheckedCell"];
    else
        cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    UILabel *from = (UILabel*) [cell.contentView viewWithTag:2];
    UILabel *subject = (UILabel*) [cell.contentView viewWithTag:3];

    from.text = rec.From;
    subject.text = rec.Subject;

    return cell;
}

私が把握できるのは、「再利用された」セルが特定の変更をサポートしているが、他の変更はサポートしていないということだけです。したがって、UILabel コントロールではさまざまなテキストがサポートされますが、UIButton コントロールではさまざまな画像がサポートされません。背景色やフォント スタイルなどの特定のプロパティに関する問題を発見した人々について読んだことがあります。

于 2012-10-01T17:12:05.030 に答える
0

やってみました

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = nil;
    // Try to dequeue
    cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    // If nothing to dequeue, create your CustomCell
    if(!cell){
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil];
        for(id currentObject in topLevelObjects){
            if([currentObject isKindOfClass:[CustomCell class]]){
                cell = (CustomCell *)currentObject;
                break;
            }
        }
    }
    UIButton *check = (UIButton*) [cell.contentView viewWithTag:1];
    UIButton *check2 = (UIButton*) [cell.selectedBackgroundView viewWithTag:1];
    UILabel *from = (UILabel*) [cell.contentView viewWithTag:2];
    UILabel *subject = (UILabel*) [cell.contentView viewWithTag:3];

    // Configure the cell...
    Message *rec = (Message*) Records[indexPath.row];
    if(rec.Checked)
        check.imageView.image = [UIImage imageNamed:@"Checkedbox.png"];
    else
        check.imageView.image = [UIImage imageNamed:@"Checkbox.png"];
    check2.imageView.image = check.imageView.image;
    from.text = rec.From;
    subject.text = rec.Subject;
    return cell;
}

を使用せずにtableView:willDisplayCell:forRowAtIndexPath:?次に、クリックするたびに[self.tableView reloadData];が呼び出され、tableView が更新さcellForRowAtIndexPath:れ、表示されているすべてのインデックス パスが呼び出されます...

于 2012-10-01T16:42:32.863 に答える