我们都知道NS_CLASS_AVAILABLE_IOS(9_0) UIStackView :UIView ,只能在iOS9以后使用,我们现在支持到iOS8的项目怎么使用呢,sunnyxx团队的FDStackView就完美的解决了这个问题,神器啊,好,鼓掌...
在FDStackView.m中嵌入了一段内联汇编,如下:
// ----------------------------------------------------
// Runtime injection start.
// Assemble codes below are based on:
// https://github.com/0xced/NSUUID/blob/master/NSUUID.m
// ----------------------------------------------------
#pragma mark - Runtime Injection
__asm(
".section __DATA,__objc_classrefs,regular,no_dead_strip\n"
#if TARGET_RT_64_BIT
".align 3\n"
"L_OBJC_CLASS_UIStackView:\n"
".quad _OBJC_CLASS_$_UIStackView\n"
#else
".align 2\n"
"_OBJC_CLASS_UIStackView:\n"
".long _OBJC_CLASS_$_UIStackView\n"
#endif
".weak_reference _OBJC_CLASS_$_UIStackView\n"
);
// Constructors are called after all classes have been loaded.
__attribute__((constructor))staticvoidFDStackViewPatchEntry(void) {
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
@autoreleasepool {
// >= iOS9.
if(objc_getClass("UIStackView")) {
return;
}
Class*stackViewClassLocation =NULL;
#if TARGET_CPU_ARM
__asm("movw %0, :lower16:(_OBJC_CLASS_UIStackView-(LPC0+4))\n"
"movt %0, :upper16:(_OBJC_CLASS_UIStackView-(LPC0+4))\n"
"LPC0: add %0, pc":"=r"(stackViewClassLocation));
#elif TARGET_CPU_ARM64
__asm("adrp %0, L_OBJC_CLASS_UIStackView@PAGE\n"
"add %0, %0, L_OBJC_CLASS_UIStackView@PAGEOFF" : "=r"(stackViewClassLocation));
#elif TARGET_CPU_X86_64
__asm("leaq L_OBJC_CLASS_UIStackView(%%rip), %0" : "=r"(stackViewClassLocation));
#elif TARGET_CPU_X86
void*pc =NULL;
__asm("calll L0\n"
"L0: popl %0\n"
"leal _OBJC_CLASS_UIStackView-L0(%0), %1":"=r"(pc),"=r"(stackViewClassLocation));
#else
#error Unsupported CPU
#endif
if(stackViewClassLocation && !*stackViewClassLocation) {
Class class = objc_allocateClassPair(FDStackView.class, "UIStackView", 0);
if(class) {
objc_registerClassPair(class);
*stackViewClassLocation = class;
}
}
}
});
}
具体源码FDStackView,有很多大佬对FDStackView有详细的解释,请自行搜索查阅。
我介绍一些实际的用法,例如项目中有个需求,有多个不同类型样式的view,后台配置不同的选项,app调用接口获得数据,来显示不同个数和位置的view,以下图随便画的,不要介意,如下图A:
现在1,2,3,4都是有可能有,有可能无,举个例子:如果把3去掉,1,2,4整体居中,如果把4去掉,1,2,3整体居中,如果把3,4去掉,1,2整体居中,如下图B,C,D。如果通过改约束,情况太多
,那么心态炸了,如果用UIStackView,简直easy的不行。
举个例子,用四个不同类型的view水平整体居中,实现照相机,银行卡,充值,提现,用StackView方便很多,看下图E,F,G
//四个不同类型的View
UIView*oneTypeView = [selfcreatViewWithImage:@"camera"text:@"照相机"];
UIView*twoTypeView = [selfcreatViewWithImage:@"bankcard"text:@"银行卡"];
UIView*threeTypeView = [selfcreatViewWithImage:@"charge"text:@"充值"];
UIView*fourTypeView = [selfcreatViewWithImage:@"crash"text:@"提现"];
UIStackView*stackView = [[UIStackViewalloc]initWithArrangedSubviews:@[oneTypeView,fourTypeView]];
stackView.translatesAutoresizingMaskIntoConstraints = NO;
//Axis表示StackView的subview是水平排布还是垂直排布
stackView.axis = UILayoutConstraintAxisHorizontal;
//Distribution定义subview的分布方式
stackView.distribution = UIStackViewDistributionFill;
//Alignment控制subview对齐方式。
stackView.alignment = UIStackViewAlignmentFill;
//Spacing 为subview间的最小间距。
stackView.spacing=15;
[self.viewaddSubview:stackView];
//约束stackView
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:stackView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:stackView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
总体而言,UIStackView是利用UIView类的intrinsicContentSize来计算布局,UIStackView实现有对齐要求和不同位置的视图布局非常得简单,平时多使用UIStackView,肯定有意想不到的收获。