Hallo, ich entwickle eine iPhone-Anwendung, in der ich versucht habe, einen Seitenrand für edittext festzulegen. Ich habe das folgendermaßen gemacht:
int borderWidth = 1;
CALayer *leftBorder = [CALayer layer];
leftBorder.borderColor = [UIColor whiteColor].CGColor;
leftBorder.borderWidth = borderWidth;
leftBorder.frame = CGRectMake(0, textField.frame.size.height - borderWidth, textField
.frame.size.width, borderWidth);
[textField.layer addSublayer:leftBorder];
Ich habe meinem Edittext in IB einige Einschränkungen auferlegt, damit beim Drehen meines Geräts die Breite des Textfelds entsprechend angepasst wird. Mein Problem ist, dass die Breite von edittext angepasst wird und nicht die Breite von CALayer, die ich für meinen Bearbeitungstext festgelegt habe. Ich denke, ich muss auch einige Einschränkungen für meinen CALayer-Gegenstand festlegen. Aber ich weiß nicht, wie ich das machen soll. Weiß jemand davon? Brauchen Sie Hilfe. Vielen Dank.
ios
autolayout
calayer
Nilkash
quelle
quelle
Antworten:
Das gesamte Autoresizing-Geschäft ist ansichtsspezifisch. Ebenen werden nicht automatisch angepasst.
Was Sie tun müssen - im Code - ist, die Größe der Ebene selbst zu ändern
z.B
in einem viewController würden Sie tun
- (void) viewDidLayoutSubviews { [super viewDidLayoutSubviews]; //if you want superclass's behaviour... // resize your layers based on the view's new frame self.editViewBorderLayer.frame = self.editView.bounds; }
oder in einer benutzerdefinierten UIView, die Sie verwenden könnten
- (void)layoutSubviews { [super layoutSubviews]; //if you want superclass's behaviour... (and lay outing of children) // resize your layers based on the view's new frame layer.frame = self.bounds; }
quelle
In
Swift 5
können Sie die folgende Lösung ausprobieren:Verwenden Sie KVO für den unten angegebenen Pfad "YourView.bounds".
self.addObserver(self, forKeyPath: "YourView.bounds", options: .new, context: nil)
Behandeln Sie es dann wie unten angegeben.
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "YourView.bounds" { YourLayer.frame = YourView.bounds return } super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) }
Mehr Infos dazu hier
quelle
Nach dieser Antwort
layoutSubviews
wird nicht in allen benötigten Fällen angerufen. Ich habe diese Delegatenmethode für effektiver befunden:- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if(self != nil) { [self.layer addSublayer:self.mySublayer]; } return self; } - (void)layoutSublayersOfLayer:(CALayer*)layer { self.mySublayer.frame = self.bounds; }
quelle
Ich habe die Methode layoutSubviews meiner benutzerdefinierten Ansicht implementiert. Bei dieser Methode aktualisiere ich einfach den Frame jeder Unterschicht, um ihn an die aktuellen Grenzen der Ebene meiner Unteransicht anzupassen.
-(void)layoutSubviews{ sublayer1.frame = self.layer.bounds; }
quelle
Meine Lösung, wenn ich mit gestricheltem Rand erstelle
class DashedBorderView: UIView { let dashedBorder = CAShapeLayer() override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() } private func commonInit() { //custom initialization dashedBorder.strokeColor = UIColor.red.cgColor dashedBorder.lineDashPattern = [2, 2] dashedBorder.frame = self.bounds dashedBorder.fillColor = nil dashedBorder.cornerRadius = 2 dashedBorder.path = UIBezierPath(rect: self.bounds).cgPath self.layer.addSublayer(dashedBorder) } override func layoutSublayers(of layer: CALayer) { super.layoutSublayers(of: layer) dashedBorder.path = UIBezierPath(rect: self.bounds).cgPath dashedBorder.frame = self.bounds } }
quelle
Swift 3.x KVO Solution (Aktualisierte Antwort von @ arango_86)
Beobachter hinzufügen
self.addObserver( self, forKeyPath: "<YOUR_VIEW>.bounds", options: .new, context: nil )
Werte beachten
override open func observeValue( forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer? ) { if (keyPath == "<YOUR_VIEW.bounds") { updateDashedShapeLayerFrame() return } super.observeValue( forKeyPath: keyPath, of: object, change: change, context: context ) }
quelle
Wenn ich KVO anwenden muss, mache ich es lieber mit RxSwift (Nur wenn ich es für mehr Dinge verwende, füge diese Bibliothek nicht nur dafür hinzu.)
Sie können KVO auch mit dieser Bibliothek anwenden, oder in der,
viewDidLayoutSubviews
aber ich habe damit bessere Ergebnisse erzielt.view.rx.observe(CGRect.self, #keyPath(UIView.bounds)) .subscribe(onNext: { [weak self] in guard let bounds = $0 else { return } self?.YourLayer.frame = bounds }) .disposed(by: disposeBag)
quelle
Riffing off arango_86s Antwort - Wenn Sie den KVO-Fix in Ihrer eigenen UIView-Unterklasse anwenden, ist es "schneller", dies zu überschreiben
bounds
unddidSet
wie folgt zu verwenden :override var bounds: CGRect { didSet { layer.frame = bounds } }
quelle
Ich hatte ein ähnliches Problem - ich musste den Rahmen eines 'CALayer' festlegen, wenn ich das automatische Layout mit Ansichten verwendete (im Code, nicht IB ).
In meinem Fall hatte ich eine leicht verschlungene Hierarchie mit einem Ansichts-Controller innerhalb eines Ansichts-Controllers. Ich kam zu dieser SO-Frage und untersuchte den Ansatz der Verwendung
viewDidLayoutSubviews
. Das hat nicht funktioniert. Nur für den Fall, dass Ihre Situation meiner ähnlich ist, habe ich Folgendes gefunden ...Überblick
Ich wollte den Rahmen für den
CAGradientLayer
vonUIView
mir als Unteransicht positionierten Rahmen innerhalb eines unterUIViewController
Verwendung von automatischen Layoutbeschränkungen festlegen .Rufen Sie die Unteransicht
gradientView
und den Ansichtscontroller aufchild_viewController
.child_viewController
war ein View Controller, den ich als eine Art wiederverwendbare Komponente eingerichtet hatte. Dasview
ofchild_viewController
wurde also zu einem übergeordneten View-Controller zusammengesetzt - nennen Sie dasparent_viewController
.Als
viewDidLayoutSubviews
ofchild_viewController
aufgerufen wurde, war dasframe
ofgradientView
noch nicht eingestellt.(An dieser Stelle würde ich empfehlen, einige
NSLog
Anweisungen zu verteilen, um ein Gefühl für die Reihenfolge der Erstellung von Ansichten in Ihrer Hierarchie usw. zu bekommen.)Also habe ich es weiter versucht
viewDidAppear
. Aufgrund der Verschachtelung vonchild_viewController
fand ichviewDidAppear
jedoch, dass nicht aufgerufen wurde.(Siehe diese SO-Frage: viewWillAppear, viewDidAppear wird nicht aufgerufen, nicht ausgelöst ).
Meine aktuelle Lösung
Ich habe hinzugefügt ,
viewDidAppear
inparent_viewController
und von dort Ich rufeviewDidAppear
inchild_viewController
.Für das anfängliche Laden brauche ich,
viewDidAppear
da erst wenn dies aufgerufen wirdchild_viewController
, alle Unteransichten ihre Frames gesetzt haben. Ich kann dann den Rahmen für dieCAGradientLayer
...Ich habe gesagt, dass dies meine aktuelle Lösung ist, weil ich damit nicht besonders zufrieden bin.
Nach dem erstmaligen Einstellen des Rahmens von
CAGradientLayer
- kann dieser Rahmen ungültig werden, wenn sich das Layout ändert - z. B. durch Drehen des Geräts.Um damit umzugehen, benutze ich
viewDidLayoutSubviews
inchild_viewController
- um den Rahmen desCAGradientLayer
InnerengradientView
korrekt zu halten.Es funktioniert, fühlt sich aber nicht gut an. (Gibt es einen besseren Weg?)
quelle