9

Impress.js のサンプル プレゼンテーションの 2D トランジションを Objective C で再現しようとしています。具体的には、回転、パン、およびスケーリングです。現在、スケーリングに焦点を当てています。

サンプルプレゼンテーションで「大きな考えを視覚化する」->「小さなアイデア」が行うように、「画面を通過する」ポイントまでUILabelをスケーリングしてみました。

これは私がこれまでに試したことです:

UILabel *label = [[UILabel alloc] init];

label.text = @"Hello World!";
label.textColor = [UIColor blackColor];
label.font = [UIFont fontWithName:@"Arial" size:18.f];
[label sizeToFit];
label.center = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2);
[self.view addSubview:label];

label.contentScaleFactor *= 80;

[UIView animateWithDuration:5 animations:^{
    label.transform = CGAffineTransformScale(label.transform, 80, 80);
}];

残念ながら、これは contentScaleFactor と初期フォント サイズに応じて、約 30 ~ 60 MB の RAM を消費します。contentScaleFactor を増やさないと、テキストがぼやけて見えます。フォントサイズを大きくすると、同じくらい多くのメモリが消費されるようです。

プロファイラーでの表示は次のとおりです。

ここに画像の説明を入力

これは単一の UILabel です。

レンダリングされるテキストやトランジションの品質を犠牲にすることなく、大量のメモリを消費せずにこれを行う方法はありますか?

4

2 に答える 2

4

プロジェクトのダウンロード リンク

この再現を達成するためにクォーツを離れる必要はないと思います。あなたが説明したすべてのものと、Impress.js をいじって集めたすべてのものは、コンテナ ビュー内で自由に移動できるコンテナ ビューに追加された一連の UILabels に変換 (ほとんどが 2D、一部は 3D) を適用することで複製できるようです。メインビュー。

これを行うために、私が作成したプロジェクトでは、UILabel「ImpressLabel」というタイトルのサブクラスを追加の init 関数とともに使用します。この関数では、ラベルにフレームを渡す代わりに、サイズ、中心点、およびCGFloatZ 軸上のラベルの回転を指定します。 . この変換は、インスタンス化時にラベルに適用されるため、ラベルを設定すると、指定した位置と変換で既に画面に表示されます。

次に、テキストの構成に関する限り、NSAttributedStringa の代わりにラベル an を渡すことができますNSString。これにより、文字列のさまざまな部分を個別に変更できるため、ラベル内のさまざまな単語をさまざまなサイズ、フォント、色、背景色などにすることができます。上記の 2 つの段落の例を次に示します。

ImpressLabel *label1 = [[ImpressLabel alloc] initWithSize:CGSizeMake(260.0f, 80.0f) andCenterPointInSuperview:CGPointMake(500.0f, 500.0f) andRotationInSuperview:0.0f andEndingScaleFactor:1.3];

NSMutableAttributedString *firstLabelAttributes = [[NSMutableAttributedString alloc] initWithString:@"then you should try\nimpress.js*\n* no rhyme intended"];

[firstLabelAttributes addAttribute:NSFontAttributeName
                             value:[UIFont systemFontOfSize:label1.font.pointSize - 2]
                             range:NSMakeRange(0, 19)];

[firstLabelAttributes addAttribute:NSFontAttributeName
                             value:[UIFont systemFontOfSize:label1.font.pointSize - 8]
                             range:NSMakeRange(firstLabelAttributes.string.length - 19, 19)];

[firstLabelAttributes addAttribute:NSFontAttributeName
                             value:[UIFont boldSystemFontOfSize:label1.font.pointSize + 14]
                             range:NSMakeRange(23, 11)];


[label1 setNumberOfLines:3];
[label1 setAttributedText:firstLabelAttributes];
[label1 setTextAlignment:NSTextAlignmentCenter];
[containmentView addSubview:label1];

さて、操作全体の内臓の詳細に進みます。上で述べたように、このサブクラスは各ラベルにタップ ジェスチャを追加します。タップが認識されると、いくつかのことが起こります。ラベルを含むビューは、スケールを調整することでパン/バック/アウェイします。また、回転を開始し、メイン ビューでアンカー ポイントを調整して、アニメーションが停止したときに、選択したラベルが正しい向きで画面の中央に配置されるようにします。もちろん、これがすべて進行している間、選択したラベルのアルファは 1.0f に上げられ、残りのアルファは 0.25f に下げられます。

- (void)tapForRotationDetected:(UITapGestureRecognizer *)sender {
    CABasicAnimation *scale = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    [scale setToValue:[NSNumber numberWithFloat:0.8]];
    [scale setAutoreverses:YES];
    [scale setDuration:0.3];

    //Create animation to adjust the container views anchorpoint.
    CABasicAnimation *adjustAnchor = [CABasicAnimation animationWithKeyPath:@"anchorPoint"];
    [adjustAnchor setFromValue:[NSValue valueWithCGPoint:self.superview.layer.anchorPoint]];
    [adjustAnchor setToValue:[NSValue valueWithCGPoint:CGPointMake(self.center.x / self.superview.frame.size.width, self.center.y / self.superview.frame.size.height)]];
    [adjustAnchor setRemovedOnCompletion:NO];
    [adjustAnchor setFillMode:kCAFillModeForwards];

    //Create animation to rotate the container view within its superview.
    CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];

    //Create the animation group to apply these transforms
    CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
    [animationGroup setAnimations:@[adjustAnchor,rotation]];
    [animationGroup setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
    [animationGroup setDuration:0.6];

    //Apply the end results of the animations directly to the container views layer.

    [self.superview.layer setTransform:CATransform3DRotate(CATransform3DIdentity, DEGREES_TO_RADIANS(-self.rotationInSuperview), 0.0f, 0.0f, 1.0f)];
    [self.superview.layer setAnchorPoint:CGPointMake(self.center.x / self.superview.frame.size.width, self.center.y / self.superview.frame.size.height)];
    [self.superview.layer addAnimation:animationGroup forKey:@"animationGroup"];

    //Animate the alpha property of all ImpressLabels in the container view.
    [self.superview bringSubviewToFront:self];
    [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        for (ImpressLabel *label in sender.view.superview.subviews) {
            if ([label isKindOfClass:[ImpressLabel class]]) {
                if (label != self) {
                    [label setAlpha:0.25f];
                }else{
                    [label setAlpha:1.0f];
                }

            }
        }
    } completion:nil];
}

さて、あなたの質問に記載されている懸念事項のいくつかに対処します。

  1. Instruments の割り当てツールでこのプロジェクトのプロファイルを作成しましたが、全体で約 3.2 MB しか消費しないため、このアプローチは十分に効率的であると言えます。

  2. 私が提供したサンプルは、せいぜい錯覚であるスケーリング アニメーションを除いて、2D 空間でほとんどのオブジェクトをアニメーション化します。ここで行ったことは、これを行う方法の例として役立つことを意図しており、100% 完全なデモンストレーションではありません。上で述べたように、アニメーションは実際には私の専門分野ではないからです。ただし、ドキュメントに目を通すと、ラベルを 3 次元で回転させ、そのスーパービューを調整してすべてのラベルを回転させ、選択したラベルを平らなままにすることが鍵となるようですCATransform3DInvert()。それが機能するかどうかを完全に把握する時間はまだありませんが、まさにこのシナリオで必要とされているようです。

  3. ミラーリングに関する限り、すべてを適切にスケーリングすることに問題があるとは思いません。Apple のMultiple Display Programming Guideを見ると、渡されたオブジェクトはNSNotification UIScreenDidConnectNotificationオブジェクトのようUIScreenです。この場合、このディスプレイの境界を簡単に要求し、それに応じてラベルのフレームとコンテナー ビューを調整できます。

注:この例では、アンカー ポイントの座標が正しく生成されていないため、0、90、180、および -90 度の変換のみが 100% 正しくアニメーション化されます。解決策は にあるように見えますがCGPointApplyAffineTransform(<#CGPoint point#>, <#CGAffineTransform t#>)、やはり、私が望んでいたほどそれで遊ぶ時間がありませんでした。いずれにせよ、複製を始めるにはこれで十分です。

これは間違いなく私の興味をかき立てました。これに再び取り組む機会が得られたら、新しい情報でこの投稿を喜んで更新します. お役に立てれば!

于 2013-03-11T20:53:44.360 に答える
1

CALayer でテキストを描画すると役立つと思います。これに役立つライブラリは次のとおりです: https://github.com/ZaBlanc/CanvasKit 新しい CALayer でアニメーションの次のステップを描画し、それに変換します。このライブラリを使用して、必要なアニメーションを連鎖させることができます: https://github.com/yangmeyer/CPAnimationSequenceまたはこのライブラリ: https://github.com/clayallsopp/Walt

于 2013-03-11T07:09:31.867 に答える