MJRFlexStyleComponents
使用 Swift 编写的易于布局选项的滑动组件和容器。
安装
CocoaPods
如果尚未安装,请安装 CocoaPods
$ [sudo] gem install cocoapods
$ pod setup
访问您的 Xcode 项目目录,创建和编辑 Podfile,并添加 MJRFlexStyleComponents
$ cd /path/to/MyProject
$ touch Podfile
$ edit Podfile
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, ‘10.0’
use_frameworks!
pod ‘MJRFlexStyleComponents’
将 MJRFlexStyleComponents 安装到您的项目中
$ pod install
打开 .xcworkspace 文件中的项目(而不是常规的项目文件)
$ open MyProject.xcworkspace
现在您可以将 import MJRFlexStyleComponents
框架导入到您的文件中。
注意:如果需要在项目中使用 ShapeStyle 类,记得也要导入 'StyledShape'
组件
源代码中包含了一个示例项目,展示了许多功能。
每个组件都有样式选项,它们以相同的方式和相同的值配置,以便整个UI的样式一致。这些组件的目标是具有非常紧凑且仍然灵活的组件,用于在尽可能少的说明性标签的情况下设计UI。
示例显示了滑动组件,其中组件本身用于操作其他组件以查看许多功能。当然,任何组件都可以单独使用。
FlexSwitch
与UISwitch非常相似的开关。
示例
let switch = FlexSwitch()
switch.switchDelegate = self
func switchStateChanged(flexSwitch: FlexSwitch, on: Bool) {
. . .
}
FlexSlider
与UISlider非常相似的滑动条。
示例
let slider = FlexSlider()
slider.backgroundColor = .clear
slider.minimumValue = 1
slider.maximumValue = 4
slider.value = 2
slider.thumbText = nil
slider.numberFormatString = "%.0f"
slider.maximumTrackText = "Series"
slider.valueChangedBlock = {
(value, index) in
. . .
}
FlexDoubleSlider
这是一个具有两个而不是一个指位的滑动条。较低的值在任何时候都不能大于较高的值。
示例
let slider = FlexDoubleSlider()
slider.backgroundColor = UIColor.clear
slider.direction = .vertical
slider.minimumValue = 0
slider.maximumValue = 100
slider.thumbRatio = 0.1
slider.hintStyle = .rounded
slider.thumbText = nil
slider.numberFormatString = "%.1f"
slider.value = 0
slider.value2 = 100
slider.valueChangedBlock = {
(value, index) in
if index == 0 {
. . .
}
else {
. . .
}
}
FlexFlickButton
鼠标按钮是一种特殊滑动条,类似于具有多个操作的按钮。按钮可以具有垂直或水平方向,并且可以为上、主和下操作分配文本和图像。
请参阅以下示例
self.horizUtilButton = FlexFlickButton(frame: CGRect(x: 10, y: 50, width: 48, height: 48))
self.horizUtilButton?.borderColor = UIColor.MKColor.BlueGrey.P700
self.horizUtilButton?.borderWidth = 1
self.horizUtilButton?.style = FlexShapeStyle(style: .rounded)
self.horizUtilButton?.styleColor = UIColor.MKColor.BlueGrey.P100
self.horizUtilButton?.thumbStyle = FlexShapeStyle(style: .box)
self.horizUtilButton?.direction = .horizontal
self.horizUtilButton?.upperActionItem.text = "<"
self.horizUtilButton?.upperActionItem.textMaxFontSize = 28
self.horizUtilButton?.upperActionItem.textSizingType = .relativeToSlider(minSize: 8)
self.horizUtilButton?.primaryActionItem.text = "Cn"
self.horizUtilButton?.primaryActionItem.textMaxFontSize = 18
self.horizUtilButton?.lowerActionItem.text = ">"
self.horizUtilButton?.lowerActionItem.textMaxFontSize = 28
self.horizUtilButton?.lowerActionItem.textSizingType = .relativeToSlider(minSize: 8)
self.view.addSubview(self.horizUtilButton!)
示例按钮有3种状态,并且以横向方式操作。主要动作的文本是“Cn”并且通过按按钮激活。上方动作是“<“并且通过向右滑动激活。下方动作是“>”并且通过向左滑动激活。
动作通过处理程序调用
self.horizUtilButton?.actionActivationHandler = {
action in
switch action {
case .upper:
NSLog("upper action triggered")
case .primary:
NSLog("primary action triggered")
case .lower:
NSLog("lower action triggered")
}
}
滑动按钮使用了通用样式滑块组件中自动文本和图标尺寸的滑块功能。如您在上述示例中所见,文本的大小是相对于滑块组件(在此情况下为滑动按钮大小)的,同时也指定了最小和最大字体大小。您可能想使用NSAttributed字符串。可以使用通用样式滑块委托的拇指和分隔器文本方法来实现这一点。
FlexSnapStepper
Snap Stepper是一种基于通用样式滑块的步进器组件。您可以使用步进器的上方/左侧部分进行倒数,下方/右侧部分进行加数。Snap Stepper可以具有垂直或水平布局方向。
示例
self.stepper = FlexSnapStepper(frame: <some size>)
self.stepper?.stepValueChangeHandler = {
newValue in
NSLog("new value is \(newValue)")
}
self.stepper?.thumbFactory = { index in
let thumb = MutableSliderThumbItem()
thumb.color = UIColor.MKColor.BlueGrey.P100
return thumb
}
self.stepper?.style = FlexShapeStyle(style: .rounded)
self.stepper?.borderColor = UIColor.MKColor.BlueGrey.P700
self.stepper?.borderWidth = 1
使用拇指和分隔器工厂来为步进器的内部组件进行样式设计。
步进器的参数在类中进行了描述
/// The value of the stepper
open var value: Double = 0.0
/// The stepper min value. This is the value updated by the relative motion of the slider and pressing the minus and plus areas.
open var minStepperValue: Double = 0
/// The stepper max value. This is the value updated by the relative motion of the slider and pressing the minus and plus areas.
open var maxStepperValue: Double = 1
/// Use the value steps in order to control the fractional amount of change when pressing plus and minus. For example, if you specify 10, then it will take 10 taps on the plus button to step from minStepperValue to maxStepperValue.
open var valueSteps: Double = 10
/// Use the value slider factor in order to control the 'speed' of the value updates.
open var valueSlideFactor: Double = 10.0
FlexMenu
FlexMenu具有三种不同的布局类型
- 紧凑型
- 等距布局
- 动态间隔
紧凑型菜单具有用于任意数量FlexMenuItems的缩略图快捷文本和菜单标题。您可以滑动缩略图来更改选定的菜单项或按缩略图。
等距和动态间隔布局类似于熟悉的应用程序界面(iOS)中的工具栏或导航栏。
所有菜单布局都支持垂直布局,并且您可以为文本标签指定重力以旋转文本
flexMenuExample.menuItemGravity: FlexMenuItemGravity = .normal // .left or .right
紧凑型样式的简单示例(来自示例项目)
var styleMenuItems: [FlexMenuItem] = []
let styleMenuSelector = FlexMenu()
func setupStyleMenuSelectionSlider() {
let col1 = FlexMenuItem(title: "Box", titleShortcut: "B", color: UIColor.MKColor.Grey.P200, thumbColor: UIColor.MKColor.Grey.P500)
let col2 = FlexMenuItem(title: "Rounded", titleShortcut: "R", color: UIColor.MKColor.Grey.P200, thumbColor: UIColor.MKColor.Grey.P500)
let col3 = FlexMenuItem(title: "Tube", titleShortcut: "T", color: UIColor.MKColor.Grey.P200, thumbColor: UIColor.MKColor.Grey.P500)
self.styleMenuItems.append(col1)
self.styleMenuItems.append(col2)
self.styleMenuItems.append(col3)
self.styleMenuSelector.menuDataSource = self
}
// MARK: - FlexMenuDataSource
func numberOfMenuItems(menu: FlexMenu) -> Int {
return self.styleMenuItems.count
}
func menuItemForIndex(menu: FlexMenu, index: Int) -> FlexMenuItem {
return self.styleMenuItems[index]
}
func menuItemSelected(menu: FlexMenu, index: Int) {
switch index {
case 0:
self.setStyleOfDemoControls(.box)
case 1:
self.setStyleOfDemoControls(.rounded)
case 2:
self.setStyleOfDemoControls(.tube)
default:
break
}
}
FlexSeriesView
使用FlexSlider控件用于显示和编辑值图形的组件
示例(来自示例项目)
let sliderGraphView = FlexSeriesView()
func setupSliderGraphView() {
// Standard iOS UI
self.sliderGraphView.layer.borderWidth = 1.0
self.sliderGraphView.layer.borderColor = UIColor.black.cgColor
self.sliderGraphView.layer.masksToBounds = true
self.sliderGraphView.layer.cornerRadius = 10
// The graph setup
self.sliderGraphView.itemSize = 24
self.sliderGraphView.backgroundColor = UIColor.clear
self.sliderGraphView.dataSource = self
self.sliderGraphView.reloadData()
}
// MARK: - FlexSeriesViewDataSource
func dataOfSeriesAtPoint(flexSeries: FlexSeriesView, series: Int, point: Int) -> Double {
return self.dataSeries[series][point]
}
func dataChangedOfSeriesAtPoint(flexSeries: FlexSeriesView, series: Int, point: Int, data: Double) {
self.dataSeries[series][point] = data
}
func numberOfSeries(flexSeries: FlexSeriesView) -> Int {
return self.numSeries
}
func numberOfDataPoints(flexSeries: FlexSeriesView) -> Int {
return self.numDataPoints
}
FlexView
此视图类似于UIView,但支持标题和页脚标签。您可以为此视图、标题和页脚使用与所有其他组件相同的样式,并且标题/页脚也可以显示在左侧或右侧。边距可以使得标题和页脚分离背景,如果需要的话。
FlexView可以包含FlexViewMenu菜单,这些菜单通过以下方式添加:
viewMenu = ... (Omitted the code. See example from the FlexMenu section)
flexViewMenu = FlexViewMenu(menu: viewMenu, size: CGSize(width: 100, height: 18), hPos: .center, vPos: .top)
flexView.addMenu(flexViewMenu)
FlexViewMenu 的大小与是否填充菜单相关。大小中的高度将是菜单的高度。水平位置(hPos)可以是 .Left、.Right、.Center 和 .Fill。垂直位置(vPos)可以是 .Header、.Top、.Bottom 和 .Footer,并将菜单放置在 FlexView 中该位置。当选择 .Bottom(即在页脚之上)或 .Top(在页眉之下)时,FlexView 的 headerSize 和 footerSize 用作垂直偏移量。
示例(来自示例项目)
rightFlexView.headerPosition = .right
rightFlexView.backgroundInsets = UIEdgeInsetsMake(0, 15, 0, 20)
rightFlexView.headerText = "Right"
rightFlexView.footerText = "Right Footer"
rightFlexView.styleColor = UIColor.MKColor.Amber.P100
rightFlexView.header.styleColor = UIColor.MKColor.Amber.P500
rightFlexView.headerSize = 16
rightFlexView.header.style = FlexShapeStyle(style: .tube)
rightFlexView.headerClipToBackgroundShape = false
rightFlexView.header.caption.labelFont = UIFont.boldSystemFont(ofSize: 10)
rightFlexView.footer.caption.labelFont = UIFont.systemFont(ofSize: 10)
rightFlexView.header.caption.labelTextAlignment = .center
rightFlexView.footer.caption.labelTextAlignment = .center
rightFlexView.footerClipToBackgroundShape = false
rightFlexView.footer.styleColor = .clear
rightFlexView.header.caption.labelTextColor = UIColor.white
rightFlexView.footer.caption.labelTextColor = UIColor.black
rightFlexView.style = FlexShapeStyle(style: .custom(path: UIBezierPath(roundedRect: rightFlexView.bounds, cornerRadius: 10)))
此示例还展示了自定义样式选项,其中使用任意的 UIBezierPath 定义背景样式。
FlexImageView
FlexImageView 是 FlexView 的一个特殊化。这不仅是一个轻量级组件来查看图像,还显示了如何扩展 Flex 风格组件。
除了 FlexView 功能外,FlexImageView 还通过简单的接口直接向包含的 UIImageView 设置和布局图像
flexView.imageView.image = UIImage(named: "DemoImage")
flexView.imageView.contentMode = .scaleAspectFit
使用 imageViewMargins: UIEdgeInsets
向 FlexView 显示矩形的图像中添加填充。
FlexTextView
这是 FlexView 中的另一个轻量级组件,一个 UITextView。
FlexCollectionView
专门的集合查看器是一个较大的扩展,不仅包括嵌入集合查看器的 FlexView 扩展,还包括一系列单元和集合项目模型。您可以注册新的 FlexCollectionItem 和 FlexCollectionViewCell,以使用您自己的模型和单元。项目中的示例生成了上述视图。以下是在 FlexCollectionView 中当前可用的单元。图像和文本都是可选的。布局将相应调整。单元包含一个 FlexView 作为容器视图。带有标题的弹性样式也是可配置的。只需不要设置标题文本即可,如果不想在单元标题中显示。
FlexCollectionView 的示例可以在演示项目类 FlexCollectionDemoViewController
中找到。
集合代理
FlexCollectionViewDelegate 有两个函数来响应用户选择和重新排序。
func onFlexCollectionItemMoved(view: FlexCollectionView, item: FlexCollectionItem) {
}
func onFlexCollectionItemSelected(view: FlexCollectionView, item: FlexCollectionItem) {
}
收集部分
使用 addSection()
函数向您的 FlexCollectionView 添加部分。该函数返回一个部分引用,用于添加项目时使用。您还可以传递一个标题,并使用 getSection(reference)
调整部分布局。
注册自定义单元格和项目
当您想要添加自己的项目和单元格时,请使用 registerCell(itemClass: AnyClass, cellClass: AnyClass)
。这些类必须继承自 FlexCollectionItem 和 FlexCollectionViewCell。
GenericStyleSlider
这是所有其他滑块类使用的类,无论是作为超类还是作为 FlexSeriesView 的子组件。您可以直接使用通用滑块,或者从其创建其他子类。
MJRFlexBaseControl
这是所有弹性样式控制的基础类。如果您想创建一个基于本库其他组件样式和原则的控制,请扩展此控制。
致谢
源自 Yannick Loriot 的 SnappingStepper (https://github.com/yannickl/SnappingStepper.git)的代码,并受到 Boris Emorine 和 Sam Spencer 的 BEMSimpleLineGraph 启发 (https://github.com/Boris-Em/BEMSimpleLineGraph)
许可证
MJRFlexStyleComponents 使用 MIT 许可证。有关更多信息,请参阅 LICENSE 文件。