5

UITextFieldに影付きのテキストを描画したい。これを行うために、UITextFieldをサブクラス化し、drawTextInRect:次のようにメソッドを実装しました。

- (void)drawTextInRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();

    // Create shadow color
    float colorValues[] = {0.21875, 0.21875, 0.21875, 1.0};
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGColorRef shadowColor = CGColorCreate(colorSpace, colorValues);
    CGColorSpaceRelease(colorSpace);

    // Create shadow
    CGSize shadowOffset = CGSizeMake(2, 2);
    CGContextSetShadowWithColor(context, shadowOffset, 0, shadowColor);
    CGColorRelease(shadowColor);

    // Render text
    [super drawTextInRect:rect];    
}

これは、テキストフィールドが編集されていない場合に最適ですが、編集が開始されるとすぐに影が消えます。足りないものはありますか?

4

5 に答える 5

1

@jake_hetfieldの回答に触発されUITextFieldて、内部ラベルを使用して描画を行うカスタムを作成しました。チェックしてください:

ShadowTextField.h ファイル

#import <UIKit/UIKit.h>

@interface ShadowTextField : UITextField

// properties to change the shadow color & offset
@property (nonatomic, retain) UIColor *textShadowColor;
@property (nonatomic) CGSize textShadowOffset;

- (id)initWithFrame:(CGRect)frame 
               font:(UIFont *)font 
          textColor:(UIColor *)textColor 
        shadowColor:(UIColor *)shadowColor 
       shadowOffset:(CGSize)shadowOffset;

@end 

ShadowTextField.m ファイル

#import "ShadowTextField.h"

@interface ShadowTextField ()
@property (nonatomic, retain) UILabel *internalLabel;
@end

@implementation ShadowTextField
@synthesize internalLabel = _internalLabel;
@synthesize textShadowColor = _textShadowColor;
@synthesize textShadowOffset = _textShadowOffset;

- (id)initWithFrame:(CGRect)frame 
               font:(UIFont *)font 
          textColor:(UIColor *)textColor 
        shadowColor:(UIColor *)shadowColor 
       shadowOffset:(CGSize)shadowOffset
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code

        // register to my own text changes notification, so I can update the internal label
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(handleUITextFieldTextDidChangeNotification) 
                                                     name:UITextFieldTextDidChangeNotification
                                                   object:nil];

        self.font = font;
        self.textColor = textColor;

        self.textShadowColor = shadowColor;
        self.textShadowOffset = shadowOffset;
    }
    return self;
}

// when the user enter text we update the internal label 
- (void)handleUITextFieldTextDidChangeNotification
{
    self.internalLabel.text = self.text;

    [self.internalLabel sizeToFit];
}

// init the internal label when first needed
- (UILabel *)internalLabel
{
    if (!_internalLabel) {
        _internalLabel = [[UILabel alloc] initWithFrame:self.bounds];
        [self addSubview:_internalLabel];

        _internalLabel.font = self.font;
        _internalLabel.backgroundColor = [UIColor clearColor];
    }
    return _internalLabel;
}

// override this method to update the internal label color
// and to set the original label to clear so we wont get two labels
- (void)setTextColor:(UIColor *)textColor
{
    [super setTextColor:[UIColor clearColor]];

    self.internalLabel.textColor = textColor;
}

// override this method to update the internal label text
- (void)setText:(NSString *)text
{
    [super setText:text];

    self.internalLabel.text = self.text;

    [self.internalLabel sizeToFit];
}

- (void)setTextShadowColor:(UIColor *)textShadowColor
{
    self.internalLabel.shadowColor = textShadowColor;
}

- (void)setTextShadowOffset:(CGSize)textShadowOffset
{
    self.internalLabel.shadowOffset = textShadowOffset;
}

- (void)drawTextInRect:(CGRect)rect {
    // don't draw anything
    // we have the internal label for that...
}

- (void)dealloc {
    [_internalLabel release];
    [_textShadowColor release];

    [super dealloc];
}

@end  

ビューコントローラーで使用する方法は次のとおりです

- (void)viewDidLoad
{
    [super viewDidLoad];

    ShadowTextField *textField = [[ShadowTextField alloc] initWithFrame:CGRectMake(0, 0, 320, 30) 
                                                                   font:[UIFont systemFontOfSize:22.0] 
                                                              textColor:[UIColor whiteColor] 
                                                            shadowColor:[UIColor redColor] 
                                                           shadowOffset:CGSizeMake(0, 1) ] ;
    textField.text = @"This is some text";    
    textField.backgroundColor = [UIColor blackColor];
    [self.view addSubview:textField];
}
于 2012-08-10T10:31:41.790 に答える
1

次のコンポーネントのコードは次のとおりです

ここに画像の説明を入力

@interface AZTextField ()
- (void)privateInitialization;
@end

@implementation AZTextField

static CGFloat const kAZTextFieldCornerRadius = 3.0;

- (id)initWithFrame:(CGRect)frame
{

    self = [super initWithFrame:frame];
    if (!self) return nil;
    [self privateInitialization];
    return self;
}

// In case you decided to use it in a nib
- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (!self) return nil;
    [self privateInitialization];
    return self;
}

- (void)privateInitialization
{
    self.borderStyle = UITextBorderStyleNone;

    self.layer.masksToBounds = NO;
    self.layer.shadowColor = [UIColor blackColor].CGColor;
    self.layer.shadowOffset = CGSizeMake(0.0f, 5.0f);
    self.layer.shadowOpacity = 0.5f;

    self.layer.backgroundColor = [UIColor whiteColor].CGColor;
    self.layer.cornerRadius = 4;

    // This code is better to be called whenever size of the textfield changed,
    // so if you plan to do that you can add an observer for bounds property
    UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:kAZTextFieldCornerRadius];
    self.layer.shadowPath = shadowPath.CGPath;
}

@end

考慮すべき点がいくつかあります。

  • borderStyle を none に設定すると、UIKit がテキストフィールドにサブビューを配置することになります。
  • Xcode のバージョンによっては、QuartzCore をリンクしたい場合があります。#import <QuartzCore/QuartzCore.h>
  • より複雑な外観については、レイヤーのシャドウ プロパティを使用して描画コード自体をdrawRect:メソッドに移動することもできますが、特にメソッドの最後でスーパーを呼び出したくない drawRect をオーバーライドする場合は jake_hetfield が正しかった
  • テキストの描画については (コンポーネントの境界線の近くに貼り付けられていることがわかります)、 テキストとプレースホルダーをそれぞれ描画する別のdrawTextInRect:andメソッドがあります。drawPlaceholderInRect:
  • 色に UIColor メソッドを使用し、CGColor プロパティを呼び出すことができます。これにより、コードが読みやすくなり、保守が容易になります。

それが役立つことを願っています!

于 2012-08-05T12:52:56.940 に答える
0

スーパーの呼び出しを停止し、テキストを自分でレンダリングします。

于 2012-08-09T10:39:21.023 に答える
0

CALayer の標準のシャドウ プロパティを試してみましたか? 通常はこれで十分で、はるかに簡単です。通常の UITextField で次のようなことを試してください。

self.inputContainer.layer.shadowColor=[UIColor blackColor].CGColor;
self.inputContainer.layer.shadowRadius=8.0f;
self.inputContainer.layer.cornerRadius=8.0f;
self.inputContainer.layer.shadowOffset=CGSizeMake(0, 4);

もちろん、最初に QuartzCore をインポートする必要があります!

#import <QuartzCore/QuartzCore.h>
于 2012-08-10T14:28:11.937 に答える
0

ラベルの描画を自分で行うこともできます。削除する

[super drawTextInRect:rect]

代わりに、独自のラベルを描画します。私はこれを試していませんが、次のようになります。

// Declare a label as a member in your class in the .h file and a property for it:
UILabel *textFieldLabel;
@property (nonatomic, retain) UILabel *textFieldLabel;

// Draw the label
- (void)drawTextInRect:(CGRect)rect {
    if (self.textFieldLabel == nil) {
        self.textFieldLabel = [[[UILabel alloc] initWithFrame:rect] autorelease];
        [self.view addSubview:myLabel];
    }

    self.textFieldLabel.frame = rect;
    self.textFieldLabel.text = self.text;

    /** Set the style you wish for your label here **/
    self.textFieldLabel.shadowColor = [UIColor grayColor];
    self.textFieldLabel.shadowOffset = CGSizeMake(2,2);
    self.textFieldLabel.textColor = [UIColor blueColor];

    // Do not call [super drawTextInRect:myLabel] method if drawing your own text
}
于 2012-08-03T15:02:42.473 に答える