6

私のiPhoneアプリには、「詳細」ボタンで拡大/縮小したい複数行のラベルがあります。このような:

Lorem ipsum dolor sit amet, consectetur 
adipiscing elit. Donec fringilla, turpis 
in porttitor imperdiet, eros turpis...

                                "<More>"

これにアニメートする必要があります:

Lorem ipsum dolor sit amet, consectetur 
adipiscing elit. Donec fringilla, turpis 
in porttitor imperdiet, eros turpis laoreet 
magna, id tempor ante lorem pulvinar lacus.
Duis vitae nisl quis sapien dictum pellentesque.

                                "<Less>"

ラベルが大きくなるとすべての線が個別に表示され、縮小するとすべての線が個別に非表示になる効果を得ようとしています。成長はうまく機能しますが、縮小アニメーション中に3行にジャンプします。何か案は?以下のコードとプロパティ:


アニメーションの成長:

[UIView animateWithDuration:0.5 animations:^{
        view.frame = CGRectMake(startFrame.origin.x, startFrame.origin.y, startFrame.size.width, startFrame.size.height + 40.0);
    }];

縮小アニメーション:

[UIView animateWithDuration:0.5 animations:^{
        view.frame = CGRectMake(startFrame.origin.x, startFrame.origin.y, startFrame.size.width, startFrame.size.height - 40.0);
    }];

UILabelプロパティ:

  • 行:0
  • 改行:テールを切り捨てる
  • コンテンツモード:トップ
4

4 に答える 4

3

これは、自動レイアウト制約を使用し、numberOfLinesを3から0に変更することでアニメーション化できます(0は、任意の数の行を表示することを意味する特別な値です)。

ラベルには、numberOfLinesを変更すると変更される固有のサイズがあり、それらは制約に影響します。コードは次のようになります。

@IBAction func buttonTapped(sender: UIButton) {
  let numberOfLines = label.numberOfLines == 0 ? 3 : 0
  label.numberOfLines = numberOfLines
  let newTitle = numberOfLines == 0 ? "Less" : "More"    
  sender.setTitle(newTitle, forState: .Normal)
  UIView.animateWithDuration(0.5) { self.view.layoutIfNeeded() }
}

ラベルとボタンを含むビューに、アニメーションブロックにレイアウトする必要があることを伝える必要があります。

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

于 2015-12-15T12:20:21.887 に答える
1

UILabelをアニメーション化すると、説明したものと同様の結果が得られました。縮小するアニメーションのみが機能し、拡大するアニメーションはフルサイズにジャンプしました。

UITextViewも試してみましたが、それもうまくいきませんでした。

私の解決策は、coverViewという名前の別のUIViewを取得し、それをUILabelの下に配置することでした。UILabelが展開されると、アニメーション化せずにサイズが変更され、coverViewは展開された部分を非表示にします。次に、アニメーションでcoverViewのorigin.yとsize.heightが変更され、展開されたUILabelが表示されます。UILabelが縮小されると、アニメーションでcoverViewのorigin.yとsize.heightが変更され、UILabelが徐々に非表示になります。アニメーションの完了ブロックで、UILabelのフレームが縮小されたサイズにサイズ変更されます。

このためのカスタムUIViewを作成しました:AnimatedLabel。以下に完全なコードを見つけることができます。私はすぐにそれを書き、コメントしませんでしたが、理解するのは難しいことではありません。

使用方法(IBでも動作します):

// Init
AnimatedLabel *animLabel = [[AnimatedLabel alloc] initWithFrame:/*desired CGRect*/];

// Set the surroundingBackgroundColor, this color will be used for the coverView
// you should set it to the container view's backgroundColor
// IMPORTANT: transparency is not supported! (if its transparent you'll see the UILabel)
animLabel.surroundingBackgroundColor = self.view.backgroundColor;

// Set the text
animLabel.label.text = /*text text text ...*/;

// Call sizeToFit to modify the label's size to fit the text perfectly
// so that the text is not moved after the label is expanded (UILabel always
// centers the text vertically and if the label
// is not resized you will see that the text is repositioned after the animation)
[animLabel sizeToFit];

// Open the label
[animLabel open];

// Close the label
[animLabel close];

// You can resize the animLabel and the subviews will be correctly resized
animLabel.frame = /*CGRect*/;

AnimatedLabel.h

//
//  AnimatedLabel.h
//  labeltest
//
//  Created by Alpar Szotyori on 20/06/2012.
//  Use it, modify it, improve it, share it!
//

#import <UIKit/UIKit.h>

@interface AnimatedLabel : UIView

@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UIColor *surroundingBackgroundColor;
@property (nonatomic) BOOL isOpen;

// Public methods

- (void)open;
- (void)close;

@end

AnimatedLabel.m:

//
//  AnimatedLabel.m
//  labeltest
//
//  Created by Alpar Szotyori on 20/06/2012.
//  Use it, modify it, improve it, share it!
//

#import "AnimatedLabel.h"

@interface NSString (visibleText)

- (NSString*)stringVisibleInRect:(CGRect)rect withFont:(UIFont*)font constrainedToSize:(CGSize)size;

@end

@implementation NSString (visibleText)

- (NSString*)stringVisibleInRect:(CGRect)rect withFont:(UIFont*)font constrainedToSize:(CGSize)size
{
    BOOL addEllipse = NO;
    NSString *visibleString = @"";
    for (int i = 2; i <= self.length; i++)
    {
        NSString *testString = [self substringToIndex:i];
        CGSize stringSize = [testString sizeWithFont:font constrainedToSize:size];
        if (stringSize.height > rect.size.height || stringSize.width > rect.size.width) {
            addEllipse = YES;
            break;
        }

        visibleString = testString;
    }

    if (addEllipse) {
        if (visibleString.length >= 3) {
            visibleString = [[visibleString substringToIndex:visibleString.length - 3] stringByAppendingString:@"…"];
        }
    }

    return visibleString;
}

@end


@interface AnimatedLabel()

@property (nonatomic, strong) UIView *coverView;
@property (nonatomic, strong) UIColor *backgrndColor;
@property (nonatomic) CGFloat origLabelHeight;
@property (nonatomic, strong) NSString *origLabelText;
@property (nonatomic) BOOL animating;
@property (nonatomic) BOOL labelKVOSet;

- (void)changeHeight:(CGFloat)height animated:(BOOL)animated;
- (void)addKVOToLabel;
- (void)removeKVOFromLabel;

@end


@implementation AnimatedLabel

#pragma mark - Properties

@synthesize label;
@synthesize surroundingBackgroundColor = i_surroundingBackgroundColor;
@synthesize isOpen;

- (void)setSurroundingBackgroundColor:(UIColor *)surroundingBackgroundColor {
    i_surroundingBackgroundColor = surroundingBackgroundColor;
    self.coverView.backgroundColor = i_surroundingBackgroundColor;
}

#pragma mark - Initialization

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.label = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, self.frame.size.width, self.frame.size.height)];
        self.label.numberOfLines = 0;
        self.label.backgroundColor = self.backgrndColor;
        self.origLabelHeight = self.label.frame.size.height;
        [self addKVOToLabel];

        self.coverView = [[UIView alloc] initWithFrame:CGRectZero];
        self.coverView.backgroundColor = [UIColor whiteColor];

        [self addSubview:self.label];
        [self addSubview:self.coverView];

        self.animating = NO;
        self.isOpen = NO;
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.label = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, frame.size.width, frame.size.height)];
        self.label.numberOfLines = 0;
        self.label.backgroundColor = self.backgrndColor;
        self.origLabelHeight = self.label.frame.size.height;
        [self addKVOToLabel];

        self.coverView = [[UIView alloc] initWithFrame:CGRectZero];
        self.coverView.backgroundColor = [UIColor whiteColor];

        [self addSubview:self.label];
        [self addSubview:self.coverView];

        self.animating = NO;
        self.isOpen = NO;
    }
    return self;
}

#pragma mark - Overriden methods

- (void)setFrame:(CGRect)frame {
    if (!self.animating && self.isOpen) {
        self.isOpen = NO;
        [self changeHeight:self.origLabelHeight animated:NO];
        frame.size.height = self.origLabelHeight;
    }

    [super setFrame:frame];

    if (!self.animating) {        
        self.label.frame= CGRectMake(0.0, 0.0, frame.size.width, frame.size.height);
        self.origLabelHeight = self.label.frame.size.height;

        [self removeKVOFromLabel];

        NSString *visibleText = [self.origLabelText stringVisibleInRect:self.label.frame withFont:self.label.font constrainedToSize:CGSizeMake(frame.size.width, LONG_MAX)];
        self.label.text = visibleText;
        [self.label sizeToFit];

        [self addKVOToLabel];
    }
}

- (void)setBackgroundColor:(UIColor *)backgroundColor {
    [super setBackgroundColor:[UIColor clearColor]];

    self.backgrndColor = backgroundColor;

    self.label.backgroundColor = self.backgrndColor;
}

- (UIColor *)backgroundColor {
    return self.backgrndColor;
}

- (void)sizeToFit {
    [self removeKVOFromLabel];

    NSString *visibleText = [self.origLabelText stringVisibleInRect:self.label.frame withFont:self.label.font constrainedToSize:CGSizeMake(self.frame.size.width, LONG_MAX)];
    self.label.text = visibleText;
    [self.label sizeToFit];
    self.origLabelHeight = self.label.frame.size.height;

    [self addKVOToLabel];

    self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.label.frame.size.width, self.label.frame.size.height);
}

#pragma mark - KVO methods

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
     if ([keyPath isEqualToString:@"text"]) {
         self.origLabelText = [change objectForKey:NSKeyValueChangeNewKey];
     }
}

#pragma mark - Public methods

- (void)open {
    self.origLabelHeight = self.label.frame.size.height;
    [self removeKVOFromLabel];
    self.label.text = self.origLabelText;
    [self addKVOToLabel];
    [self.label sizeToFit];

    if (self.origLabelHeight == self.label.frame.size.height) {
        return;
    }

    [self changeHeight:self.label.frame.size.height animated:YES];
    self.isOpen = YES;
}

- (void)close {
    if (self.frame.size.height == self.origLabelHeight) {
        return;
    }

    [self changeHeight:self.origLabelHeight animated:YES];
    self.isOpen = NO;
}

#pragma mark - Private methods

#pragma mark - Properties

@synthesize coverView, backgrndColor, origLabelHeight, origLabelText, animating, labelKVOSet;

#pragma mark - Methods

- (void)changeHeight:(CGFloat)height animated:(BOOL)animated {
    if (self.frame.size.height == height) {
        return;
    }

    if (height > self.frame.size.height) {
        self.animating = YES;

        [self.label sizeToFit];
        height = self.label.frame.size.height;

        self.coverView.frame = CGRectMake(0.0, self.frame.size.height, self.frame.size.width, height - self.frame.size.height);
        self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, height);
        self.label.frame = CGRectMake(0.0, 0.0, self.frame.size.width, self.frame.size.height);

        if (animated) {
            [UIView animateWithDuration:0.5 animations:^(){
                self.coverView.frame = CGRectMake(0.0, self.frame.size.height, self.frame.size.width, 0.0); 
            } completion:^(BOOL completed){
                self.animating = NO;
            }];
        } else {
            self.coverView.frame = CGRectMake(0.0, self.frame.size.height, self.frame.size.width, 0.0); 
            self.animating = NO;
        }
    } else {
        self.animating = YES;

        if (animated) {
            [UIView animateWithDuration:0.5 animations:^(){
                self.coverView.frame = CGRectMake(0.0, height, self.frame.size.width, self.frame.size.height - height);
            } completion:^(BOOL completed){
                self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, height);
                self.coverView.frame = CGRectMake(0.0, height, self.frame.size.width, 0.0);
                self.label.frame = CGRectMake(0.0, 0.0, self.frame.size.width, height);
                self.animating = NO;
            }];
        } else {
            self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, height);
            self.coverView.frame = CGRectMake(0.0, height, self.frame.size.width, 0.0);
            self.label.frame = CGRectMake(0.0, 0.0, self.frame.size.width, height);
            self.animating = NO;            
        }
    }
}

- (void)addKVOToLabel {
    if (self.label == nil) {
        return;
    }

    if (!self.labelKVOSet) {
        self.labelKVOSet = YES;
        [self.label addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:nil];
    }
}

- (void)removeKVOFromLabel {
    if (self.label == nil) {
        return;
    }

    if (self.labelKVOSet) {
        self.labelKVOSet = NO;
        [self.label removeObserver:self forKeyPath:@"text"];
    }
}

@end
于 2012-06-20T14:55:18.117 に答える
1

ビューを拡大/縮小しようとしても、同様の問題が発生しました。これが私のSO投稿です。基本的に、フレームをアニメーション化して拡大し、次に境界/中心を縮小して縮小する必要がありました。少し厄介ですが、思い通りの効果が得られました。

于 2012-06-20T15:11:38.643 に答える
0

問題はあなたが投稿したコードにはありません。この問題を解決するには、より多くの情報が必要です。以下を確認することをお勧めします。

  1. サイズを変更しているビューオブジェクトが正しいものであること。
  2. サイズを変更するビューオブジェクトに色付きの背景を追加して、サイズがリアルタイムでどのように変化するかを確認できるようにします。

それでも問題が解決しない場合は、投稿したこれらのアニメーションスニペ​​ットを実行している完全なメソッドを投稿してください。

于 2012-05-27T03:55:48.707 に答える