Tôi thường thích tạo và thiết kế uiview của mình trong trình tạo giao diện. Đôi khi tôi cần tạo một chế độ xem duy nhất trong xib có thể được sử dụng lại trong nhiều bộ điều khiển chế độ xem trong bảng phân cảnh.
Tôi thường thích tạo và thiết kế uiview của mình trong trình tạo giao diện. Đôi khi tôi cần tạo một chế độ xem duy nhất trong xib có thể được sử dụng lại trong nhiều bộ điều khiển chế độ xem trong bảng phân cảnh.
Câu trả lời:
Đã thử nghiệm với Swift 2.2 & Xcode 7.3.1
// DesignableXibView.swift
import UIKit
@IBDesignable
class DesignableXibView: UIView {
var contentView : UIView?
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup() {
contentView = loadViewFromNib()
// use bounds not frame or it'll be offset
contentView!.frame = bounds
// Make the view stretch with containing view
contentView!.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(contentView!)
}
func loadViewFromNib() -> UIView! {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: String(self.dynamicType), bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
Hoạt động trong Xcode 6.3.1
Tạo một UIView mới có tên là 'ReusableView'
Tạo một tệp xib phù hợp có tên là 'ReusableView'
Đặt chủ sở hữu tệp của xib
đặt lớp tùy chỉnh thành 'ReusableView' trong Trình kiểm tra danh tính.
Tạo lối thoát từ chế độ xem trong ReusableView.xib sang giao diện ReusableView.h của bạn
Thêm triển khai initWithCoder để tải chế độ xem và thêm làm chế độ xem phụ.
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self) {
// 1. load the interface
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
// 2. add as subview
[self addSubview:self.view];
// 3. allow for autolayout
self.view.translatesAutoresizingMaskIntoConstraints = NO;
// 4. add constraints to span entire view
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:nil views:@{@"view":self.view}]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:@{@"view":self.view}]];
}
return self;
}
Kiểm tra chế độ xem có thể sử dụng lại của bạn trong bảng phân cảnh
Chạy và quan sát!
UINib(nibName: nibName, bundle: nil).instantiateWithOwner(nil, options: nil)
phiên bản này nhanh hơn Phiên bản NSBundle.
@IBDesignable on the class.
Bạn cũng phải triển khai init(frame:)
- nhưng khác với việc nó hoạt động khá tốt! supereasyapps.com/blog/2014/12/15/…
Cập nhật Swift 3 & 4 cho câu trả lời được chấp nhận
1. Tạo một UIView mới có tên 'DesignableXibView'
2. Tạo tệp xib phù hợp có tên 'DesignableXibView'
3. Đặt chủ sở hữu tệp của xib
Chọn "DesignableXibView.xib"> "Chủ sở hữu tệp"> đặt "Lớp tùy chỉnh" thành 'DesignableXibView' trong Trình kiểm tra danh tính.
4. Triển khai DesignableXibView
import UIKit
@IBDesignable
class DesignableXibView: UIView {
var contentView : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup() {
contentView = loadViewFromNib()
// use bounds not frame or it'll be offset
contentView.frame = bounds
// Make the view stretch with containing view
contentView.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
// Adding custom subview on top of our view
addSubview(contentView)
}
func loadViewFromNib() -> UIView! {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as! UIView
return view
}
}
5 Kiểm tra chế độ xem có thể sử dụng lại của bạn trong bảng phân cảnh
Mở bảng phân cảnh của bạn
Thêm chế độ xem
Đặt Lớp tùy chỉnh của chế độ xem đó
DesignableXibView
. Xây dựng dự án để xem các thay đổi.
String(describing: type(of: self))
nên làm điều này một cách an toàn
Hàm initWithCoder trong swift 2 nếu ai đó gặp sự cố khi dịch nó:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
UINib(nibName: String(self.dynamicType), bundle: NSBundle.mainBundle()).instantiateWithOwner(self, options: nil)
self.addSubview(view)
self.view.translatesAutoresizingMaskIntoConstraints = false
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[view]|", options: NSLayoutFormatOptions.AlignAllCenterY , metrics: nil, views: ["view": self.view]))
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: NSLayoutFormatOptions.AlignAllCenterX , metrics: nil, views: ["view": self.view]))
}
Chỉ chuyển đổi Swift
thành Objective-C
không đủ để làm cho nó hoạt động. Tôi đã gặp khó khăn khi cho phép hiển thị trực tiếp trong Storyboard.
Sau khi dịch toàn bộ mã, chế độ xem được tải tốt khi chạy trên thiết bị (hoặc trình mô phỏng), nhưng hiển thị trực tiếp trong Storyboard không hoạt động. Lý do cho điều này là tôi đã sử dụng [NSBundle mainBundle]
trong khi Trình tạo giao diện không có quyền truy cập vào mainBundle. Những gì bạn phải sử dụng thay thế là [NSBundle bundleForClass:self.classForCoder]
. BOOM, kết xuất trực tiếp hoạt động ngay bây giờ!
Lưu ý: nếu bạn gặp sự cố với Bố cục Tự động, hãy thử tắt Safe Area Layout Guides
trong Xib.
Để thuận tiện cho bạn, tôi để lại toàn bộ mã của tôi ở đây, để bạn chỉ cần sao chép / dán (đối với tất cả quá trình, hãy làm theo câu trả lời gốc ):
BottomBarView.h
#import <UIKit/UIKit.h>
IB_DESIGNABLE
@interface BottomBarView : UIView
@end
BottomBarView.m
#import "BottomBarView.h"
@interface BottomBarView() {
UIView *contentView;
}
@end
@implementation BottomBarView
-(id) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self xibSetup];
}
return self;
}
-(id) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self xibSetup];
}
return self;
}
-(void) xibSetup {
contentView = [self loadViewFromNib];
contentView.frame = self.bounds;
contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:contentView];
}
-(UIView*) loadViewFromNib {
NSBundle *bundle = [NSBundle bundleForClass:self.classForCoder]; //this is the important line for view to render in IB
UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:bundle];
UIView *view = [nib instantiateWithOwner:self options:nil][0];
return view;
}
@end
Hãy cho tôi biết nếu bạn gặp phải một số vấn đề nhưng nó gần như sẽ hoạt động tốt :)
Nếu ai đó quan tâm, đây là phiên bản Xamarin.iOS của mã Bước 4 của @Garfbargle
public partial class CustomView : UIView
{
public ErrorView(IntPtr handle) : base(handle)
{
}
[Export("awakeFromNib")]
public override void AwakeFromNib()
{
var nibObjects = NSBundle.MainBundle.LoadNib("CustomView", this, null);
var view = (UIView)Runtime.GetNSObject(nibObjects.ValueAt(0));
view.Frame = Bounds;
view.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
AddSubview(rootView);
}
}
Đây là câu trả lời mà bạn mong muốn. Bạn chỉ có thể tạo CustomView
lớp của mình , có phiên bản chính của nó trong một xib với tất cả các chế độ xem phụ và cửa hàng. Sau đó, bạn có thể áp dụng lớp đó cho bất kỳ trường hợp nào trong bảng phân cảnh của mình hoặc các xib khác.
Không cần phải loay hoay với Chủ sở hữu tệp, hoặc kết nối các cửa hàng với proxy hoặc sửa đổi xib theo cách đặc biệt hoặc thêm một phiên bản của chế độ xem tùy chỉnh của bạn làm chế độ xem phụ của chính nó.
Chỉ cần làm điều này:
UIView
thành NibView
(hoặc từ UITableViewCell
thành NibTableViewCell
)Đó là nó!
Nó thậm chí hoạt động với IBDesignable để hiển thị chế độ xem tùy chỉnh của bạn (bao gồm các chế độ xem phụ từ xib) tại thời điểm thiết kế trong bảng phân cảnh.
Bạn có thể đọc thêm về nó tại đây: https://medium.com/build-an-app-like-lego/embed-a-xib-in-a-storyboard-953edf274155
Và bạn có thể tải khung công tác BFWControls mã nguồn mở tại đây: https://github.com/BareFeetWare/BFWControls
Tom 👣