2015年4月アーカイブ

複数行対応のUITableViewCellを使用するときなど、自動的にセル高さを決定してくれるUITableViewAutomaticDimensionは非常に便利です。
便利なのですが画面回転などによりUITableViewの(内部Cellの)frameが変わってしまう場合、正しい高さを求めてくれなくなってしまいます。
UITableView.frameの変更に合わせて次のおまじないを唱えることで、簡単に対応することが可能です。

[UITableView beginUpdates];

[UITableView endUpdates];


NSMutableArrayに標準で用意されていない、項目の移動メソッドを拡張で実装します。

[NSMutableArray+MoveObject.h]

@interface NSMutableArray (MoveObject)


- (void)moveObjectFromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex;


@end


[NSMutableArray+MoveObject.m]

@implementation NSMutableArray (MoveObject)


- (void)moveObjectFromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex

{

if (fromIndex > toIndex) {

id dummy = [[[NSObject alloc] init] autorelease];

id obj = [self objectAtIndex:fromIndex];

[self insertObject:dummy atIndex:fromIndex];

[self removeObject:obj];

[self insertObject:obj atIndex:toIndex];

[self removeObject:dummy];

}

else if (toIndex > fromIndex) {

id obj = [self objectAtIndex:fromIndex];

[self removeObject:obj];

[self insertObject:obj atIndex:toIndex];

}

}


@end


使用例は次の通りです。
UITableViewでCellの移動を行い、データソースであるNSMutableArrayを適正な順序に並び替える処理を想定しています。

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath

{

[self.dataList moveObjectFromIndex:sourceIndexPath.row toIndex:destinationIndexPath.row];

}



通常UIViewに枠線を付ける場合、次のプロパティを設定するだけで実現可能です。
UIView.layer.borderColor = [UIColor whiteColor].CGColor;
UIView.layer.borderWidth = 1.0;
とても簡単ですが、このプロパティを使うと必ずUIViewの縁4辺に枠線が引かれます。
例えば左側1辺のみに枠線を付けるなどどいう事はできません。

今回は縁4辺それぞれに対して枠線の表示/非表示を切り替え可能なUIViewを設計します。

BorderExView.h

// 枠強調オプション

typedef NS_OPTIONS(NSUInteger, eBorderEmphasisOption)

{

BorderEmphasisOption_None = 0,

BorderEmphasisOption_Top = 1 << 0,

BorderEmphasisOption_Bottom = 1 << 1,

BorderEmphasisOption_Left = 1 << 2,

BorderEmphasisOption_Right = 1 << 3,

BorderEmphasisOption_All = NSUIntegerMax

};


@interface BorderExView : UIView


@property (nonatomic) eBorderEmphasisOption borderEmphasis;

@property (nonatomic, strong) UIColor* borderColor;

@property (nonatomic) float borderWidth;


@end


BorderExView.m

@interface BorderExView ()

{

eBorderEmphasisOption _borderEmphasis;

}


@end


@implementation BorderExView


@synthesize borderColor = _borderColor;

@synthesize borderWidth = _borderWidth;


@dynamic borderEmphasis;

- (eBorderEmphasisOption)borderEmphasis

{

return _borderEmphasis;

}

- (void)setBorderEmphasis:(eBorderEmphasisOption)borderEmphasis

{

_borderEmphasis = borderEmphasis;

[self setNeedsDisplay];

}


- (id)initWithFrame:(CGRect)frame

{

if (self = [super initWithFrame:frame]) {

_borderEmphasis = BorderEmphasisOption_None;

self.borderColor = [UIColor blackColor];

self.borderWidth = 1.0;

}

return self;

}


- (void)drawRect:(CGRect)rect

{

CGContextRef ctx = UIGraphicsGetCurrentContext();

CGContextSetLineWidth(ctx, self.borderWidth);

CGContextSetStrokeColorWithColor(ctx, self.borderColor.CGColor);

if (self.borderEmphasis & BorderEmphasisOption_Top) {

CGContextMoveToPoint(ctx, 0, 0);

CGContextAddLineToPoint(ctx, self.frame.size.width, 0);

CGContextStrokePath(ctx);

}

if (self.borderEmphasis & BorderEmphasisOption_Bottom) {

CGContextMoveToPoint(ctx, 0, self.frame.size.height);

CGContextAddLineToPoint(ctx, self.frame.size.width, self.frame.size.height);

CGContextStrokePath(ctx);

}

if (self.borderEmphasis & BorderEmphasisOption_Left) {

CGContextMoveToPoint(ctx, 0, 0);

CGContextAddLineToPoint(ctx, 0, self.frame.size.height);

CGContextStrokePath(ctx);

}

if (self.borderEmphasis & BorderEmphasisOption_Right) {

CGContextMoveToPoint(ctx, self.frame.size.width, 0);

CGContextAddLineToPoint(ctx, self.frame.size.width, self.frame.size.height);

CGContextStrokePath(ctx);

}

}


@end


使い方は次の通りです。

BorderExView* view = [[BorderExView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];

[self.view addSubview:view];

view.backgroundColor = [UIColor yellowColor];

view.borderColor = [UIColor grayColor];

view.borderWidth = 5.0;

view.borderEmphasis = BorderEmphasisOption_Left | BorderEmphasisOption_Top;