3

テーブル ビューの UITableViewCell を、セルの左上隅を斜めに横断するスタンプのようなテキスト バナーで装飾しようとしています。

おそらく完全に間違った場所でこれを行っています-layoutSubviewsが、レイヤーを追加するためにオーバーライドしています。私はそれをやろうとしました-drawRect:が、テーブルがレンダリングされると、バナーはテーブルビューのimageViewで覆われてしまいます(つまり、イメージビューが後で追加されるため、レイヤーはイメージビューの下にあります)。

私はこれを正しく計算するのに本当に苦労しています。私が計算したところ、バナーがセルの上から 40 ポイント、左から 40 ポイントで開始し、正確に -45 度の角度であると仮定すると、斜辺は 56 ポイントになります。だから私は CALayer を 56 ポイント幅にして、それを -45º 回転させています。問題は、セル内の位置です...セルの端に強くぶつかるのではなく、セルの外側に座っています。

これを適切な場所に配置するために試行錯誤を適用するのではなく、誰かが数学を手伝ってくれませんか? 明らかに、レイヤーを移動して回転させる必要があります

ここで必要なのは anchorPoint のように感じますが、それは実際にレイヤーを動かしているように見えるので、ポイントを逃しているに違いありません (しゃれた意図はありません)。

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.imageView.frame = CGRectMake(10, 10, 50, 50);

    if (self.hasBanner) {
        CALayer *banner = [CALayer layer];
        banner.backgroundColor = [UIColor colorWithRed:.5f green:.5f blue:.5f alpha:1.f].CGColor;
        banner.frame = CGRectMake(0, 40-15, 56, 15);
        banner.anchorPoint = CGPointMake(0, 1); // this just makes it worse
        banner.transform = CATransform3DMakeRotation(-45.0 / 180.0 * M_PI, 0.0, 0.0, 1.0);
        [self.layer addSublayer:banner];
    }
}

バナーが間違った場所にある

4

1 に答える 1

8

レイヤーはどこに行くべきですか?

ダイアグラムを描きましょう:

ここに画像の説明を入力してください

さらに進んでトリガーを行うこともできますが、ここで停止しましょう。バナーの真ん中のポイントがにある必要があることはかなり明白です(20,20)。CoreAnimationにまさにそれを行うように指示できます。

レイヤーの配置

4つの別々のステップの観点から考えてください。

  1. レイヤーのサイズを設定します
  2. レイヤー内のどのポイントが便利な参照ポイントであるかを決定します
  3. その基準点の位置を設定します
  4. 参照点を中心にレイヤーを回転します

これらは、、、、およびの4つのプロパティに対応boundsanchorPointます。positiontransform

frameプロパティの値は、、、、、およびから派生しているため、プロパティに触れboundsないpositionでください。を設定しようとすると、CALayerはを反転しようとし、それを指定したrectに適用してから、とを設定します。それはあなたが望む結果を与えないかもしれないので、あなたはそれを完全に無視する方が良いです-そのように混乱することは少なくなります。transformanchorPointframetransformboundsposition

(詳細については、 『Core Animationガイド』、特に「レイヤーオブジェクトが独自のジオメトリを定義する」セクションを参照してください。)

コードでは、次のことを行います。

  1. boundsrectに設定し0, 0, width, heightます。(私は意図的にあなたに任せwidthます-それは56以上でなければならないでしょう。)
  2. anchorPointポイントに設定します0.5, 0。つまり、レイヤーの幅の途中、およびレイヤーの最上部にあります。
  3. positionポイントに設定します20, 20
  4. transform45°回転するように設定します。

ちなみに、以下のコードでは、単純な2D変換に少し便利であるという理由だけaffineTransformで、の代わりに設定しています。transform

レイヤーを設定するタイミング

あなたは正しいです、それ-drawRect:はレイヤーを作成して追加するのに間違った場所です。そのメソッドは、ビューのコンテンツ(そのCGContext)に引き込む必要がありますが、他にはもしません。

layoutSubviewsは機能しますが、予想よりも頻繁に呼び出されるため、毎回新しいレイヤーを作成して追加する必要はありません。

レイヤーのジオメトリを一度設定するだけで、二度と触れないように見えます。hasBannerプロパティが変更されたときに、レイヤーを作成または破棄してみませんか?

@interface MyTableViewCell ()

@property (nonatomic) BOOL hasLayer;
@property (nonatomic) CALayer* bannerLayer;

@end

- (void)setHasBanner:(BOOL)hasBanner
{
    if (hasBanner != _hasBanner) {
        _hasBanner = hasBanner;

        if (hasBanner) {
            CALayer* banner = [CALayer layer];
            banner.backgroundColor = [UIColor colorWithRed:.5f green:.5f blue:.5f alpha:1.f].CGColor;

            banner.bounds = CGRectMake(0, 0, 56, 15);
            banner.anchorPoint = CGPointMake(0.5, 0);
            banner.position = CGPointMake(20, 20);
            banner.affineTransform = CGAffineTransformMakeRotation(-45.0 / 180.0 * M_PI);

            // Add the layer to the view, and remember it for later
            [self.layer addSublayer:banner];
            self.bannerLayer = banner;
        } else {
            // Remove the layer from the view, and discard it
            [self.bannerLayer removeFromSuperlayer];
            self.bannerLayer = nil;
        }
    }
}
于 2013-02-03T06:25:20.297 に答える