この質問は、もともとObjective-Cプログラミング言語に対して尋ねられました。執筆時点では、Swiftはまだ存在していませんでした。
CGRect
のoneプロパティのみを変更することは可能ですか?
例えば:
self.frame.size.width = 50;
の代わりに
self.frame = CGRectMake(self.frame.Origin.x,
self.frame.Origin.y,
self.frame.size.width,
50);
もちろん、self.frame.size.width
はread onlyですので、どうすればいいのでしょうか?
CSS ANALOGYご自身の責任で進めてください
CSS
に精通している人にとっては、アイデアは次のものを使用することに非常に似ています。
margin-left: 2px;
値全体を変更する代わりに:
margin: 5px 5px 5px 2px;
元の質問に答えるために、はい、CGRect
構造体のメンバーを1つだけ変更することができます。このコードはエラーをスローしません:
myRect.size.width = 50;
notは可能ですが、それ自体が別のオブジェクトのプロパティであるCGRect
の単一のメンバーを変更することです。その非常に一般的なケースでは、一時ローカル変数を使用する必要があります。
CGRect frameRect = self.frame;
frameRect.size.width = 50;
self.frame = frameRect;
この理由は、プロパティアクセサーself.frame = ...
を使用することは[self setFrame:...]
と同等であり、このアクセサーは常にCGRect
全体を想定しているためです。この場合、Cスタイルのstruct
アクセスとObjective-Cプロパティのドット表記を組み合わせることはうまく機能しません。
Ahmed Khalaf's answer が好きでしたが、いくつかのC関数を書き出すだけでもいいことがわかりました...主な利点は、イベントのエラーを簡単に追跡できることです。間違ったタイプを使用していること。
そうは言っても、これらの関数宣言を使用して.hファイルを作成しました。
CGRect CGRectSetWidth(CGRect rect, CGFloat width);
CGRect CGRectSetHeight(CGRect rect, CGFloat height);
CGRect CGRectSetSize(CGRect rect, CGSize size);
CGRect CGRectSetX(CGRect rect, CGFloat x);
CGRect CGRectSetY(CGRect rect, CGFloat y);
CGRect CGRectSetOrigin(CGRect rect, CGPoint Origin);
そして、これらの関数実装を含む対応する.mファイル:
CGRect CGRectSetWidth(CGRect rect, CGFloat width) {
return CGRectMake(rect.Origin.x, rect.Origin.y, width, rect.size.height);
}
CGRect CGRectSetHeight(CGRect rect, CGFloat height) {
return CGRectMake(rect.Origin.x, rect.Origin.y, rect.size.width, height);
}
CGRect CGRectSetSize(CGRect rect, CGSize size) {
return CGRectMake(rect.Origin.x, rect.Origin.y, size.width, size.height);
}
CGRect CGRectSetX(CGRect rect, CGFloat x) {
return CGRectMake(x, rect.Origin.y, rect.size.width, rect.size.height);
}
CGRect CGRectSetY(CGRect rect, CGFloat y) {
return CGRectMake(rect.Origin.x, y, rect.size.width, rect.size.height);
}
CGRect CGRectSetOrigin(CGRect rect, CGPoint Origin) {
return CGRectMake(Origin.x, Origin.y, rect.size.width, rect.size.height);
}
だから、今、あなたがしたいことをするために、あなたはただすることができます:
self.frame = CGRectSetWidth(self.frame, 50);
均等になるFancier(1年後に行った更新)
これには冗長なself.frame
しかし、その中。これを修正するには、次のようなメソッドを使用してcategory
にUIView
を追加できます。
- (void) setFrameWidth:(CGFloat)width {
self.frame = CGRectSetWidth(self.frame, width); // You could also use a full CGRectMake() function here, if you'd rather.
}
そして今、あなたはちょうど入力することができます:
[self setFrameWidth:50];
または、さらに良い:
self.frameWidth = 50;
そして、次のようなことができます。
self.frameWidth = otherView.frameWidth; // as opposed to self.frameWidth = otherView.frame.size.width;
カテゴリにもこれが必要です:
- (CGFloat) frameWidth {
return self.frame.size.width;
}
楽しい。
ArtOfWarfareのソリューション (これは本当に素晴らしい)に基づいて、C関数なしでUIView
カテゴリーを構築しました。
使用例:
[self setFrameWidth:50];
self.frameWidth = 50;
self.frameWidth += 50;
self.frameWidth = otherView.frameWidth; // as opposed to self.frameWidth = otherView.frame.size.width;
ヘッダーファイルUIView+easy_frame.h
:
@interface UIView (easy_frame)
- (void) setFrameWidth:(CGFloat)width;
- (void) setFrameHeight:(CGFloat)height;
- (void) setFrameX:(CGFloat)x;
- (void) setFrameY:(CGFloat)y;
- (CGFloat) frameWidth;
- (CGFloat) frameHeight;
- (CGFloat) frameX;
- (CGFloat) frameY;
実装ファイルUIView+easy_frame.m
:
#import "UIView+easy_frame.h"
@implementation UIView (easy_frame)
# pragma mark - Setters
- (void) setFrameWidth:(CGFloat)width
{
self.frame = CGRectMake(self.frame.Origin.x,
self.frame.Origin.y,
width,
self.frame.size.height);
}
- (void) setFrameHeight:(CGFloat)height
{
self.frame = CGRectMake(self.frame.Origin.x,
self.frame.Origin.y,
self.frame.size.width,
height);
}
- (void) setFrameX:(CGFloat)x
{
self.frame = CGRectMake(x,
self.frame.Origin.y,
self.frame.size.width,
self.frame.size.height);
}
- (void) setFrameY:(CGFloat)y
{
self.frame = CGRectMake(self.frame.Origin.x,
y,
self.frame.size.width,
self.frame.size.height);
}
# pragma mark - Getters
- (CGFloat) frameWidth
{
return self.frame.size.width;
}
- (CGFloat) frameHeight
{
return self.frame.size.height;
}
- (CGFloat) frameX
{
return self.frame.Origin.x;
}
- (CGFloat) frameY
{
return self.frame.Origin.y;
}
このような個々のコンポーネントの変更を行う必要がある場合は、次のようなマクロをすべてのコードからアクセスできるようにする価値があります。
#define CGRectSetWidth(rect, w) CGRectMake(rect.Origin.x, rect.Origin.y, w, rect.size.height)
#define ViewSetWidth(view, w) view.frame = CGRectSetWidth(view.frame, w)
この方法では、幅だけを変更する必要があるときはいつでも、次のように書くだけです。
ViewSetWidth(self, 50);
の代わりに
self.frame = CGRectMake(self.frame.Origin.x, self.frame.Origin.y, self.frame.size.width, 50);
N0_quarterの回答に基づいて、Swiftで書かれたUIView拡張機能を次に示します。
/**
* Convenience category for manipulating UIView frames
*/
extension UIView {
//MARK: - Getters
func frameX() -> CGFloat {
return frame.Origin.x
}
func frameY() -> CGFloat {
return frame.Origin.y
}
func frameWidth() -> CGFloat {
return frame.size.width
}
func frameHeight() -> CGFloat {
return frame.size.height
}
//MARK: - Setters
func setFrameX(x: CGFloat) {
frame = CGRect(x: x, y: frame.Origin.y, width: frame.size.width, height: frame.size.height)
}
func setFrameY(y: CGFloat) {
frame = CGRect(x: frame.Origin.x, y: y, width: frame.size.width, height: frame.size.height)
}
func setFrameWidth(width: CGFloat) {
frame = CGRect(x: frame.Origin.x, y: frame.Origin.y, width: width, height: frame.size.height)
}
func setFrameHeight(height: CGFloat) {
frame = CGRect(x: frame.Origin.x, y: frame.Origin.y, width: frame.size.width, height: height)
}
}
Swiftでは、アプリのUIViewクラスを拡張して、たとえば次のようにテーブルヘッダービューを10ポイント上げることができます。
tableView.tableHeaderView!.frameAdj(0, -20, 0, 0)
(もちろん、AutoLayoutを使用している場合、実際には何もしないかもしれません... :))
UIViewを拡張することにより(アプリ内のすべてのUIViewとそのサブクラスに影響します)
extension UIView {
func frameAdj(x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) {
self.frame = CGRectMake(
self.frame.Origin.x + x,
self.frame.Origin.y + y,
self.frame.size.width + width,
self.frame.size.height + height)
}
}
setFrameメソッドを頻繁に呼び出すことは、次のようにあまり良くありません:setFrameX(x) setFrameY(y) setFrameWidth(width) ...
代わりに、Swiftでは、デフォルトのパラメーターを使用して、1回の呼び出しでのみ複数のパラメーターを設定できます。
func setFrame(x x: CGFloat = CGFloat.NaN, y: CGFloat = CGFloat.NaN, width: CGFloat = CGFloat.NaN, height: CGFloat = CGFloat.NaN) {
let newX = x.isNaN ? self.frame.Origin.x : x
let newY = y.isNaN ? self.frame.Origin.y : y
let newWidth = width.isNaN ? self.bounds.size.width : width
let newHeight = height.isNaN ? self.bounds.size.height : height
self.frame = CGRect(x: newX, y: newY, width: newWidth, height: newHeight)
}
次に、フレームの更新パラメータのみが必要です:
setFrame(x: x, width: min(maxX - x, titleLabel.bounds.size.width))
setFrame(width: titleDescriptionLabel.bounds.size.width + 5, height: titleDescriptionLabel.bounds.size.height + 6)
私はパーティーに遅すぎないことを願っています、ここにObjCでの私の解決策があります。
私にとっては、いくつかの関数ではなく単一の関数に固執することを好み、ポスターに示されているCSSアプローチが好きです。以下は、UIViewカテゴリに追加する関数です。
- (void)resetFrame:(CGRect)frame {
CGRect selfFrame = self.frame;
selfFrame.Origin = CGPointMake(frame.Origin.x>0 ? frame.Origin.x : selfFrame.Origin.x, frame.Origin.y>0 ? frame.Origin.y : selfFrame.Origin.y);
selfFrame.size = CGSizeMake(frame.size.width>0 ? frame.size.width : selfFrame.size.width, frame.size.height>0 ? frame.size.height : selfFrame.size.height);
[self setFrame:selfFrame]; }
例に示すように、提供されたCGRectの各値を調べ、値が0より大きい場合、その値を置き換えることを意味します。したがって、CGRect(0,0,100,0)を実行でき、幅のみを置き換えたいと仮定します。