Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Divider as UIView #1262

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
320 changes: 158 additions & 162 deletions Sources/iOS/Divider/Divider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,183 +34,179 @@ public enum DividerAlignment: Int {
case right
}

public struct Divider {
/// A reference to the UIView.
internal weak var view: UIView?

/// A reference to the divider UIView.
internal var line: UIView?

/// A reference to the height.
public var thickness: CGFloat {
didSet {
reload()
}
}

/// A preset wrapper around contentEdgeInsets.
public var contentEdgeInsetsPreset = EdgeInsetsPreset.none {
didSet {
contentEdgeInsets = EdgeInsetsPresetToValue(preset: contentEdgeInsetsPreset)
}
}

/// A reference to EdgeInsets.
public var contentEdgeInsets = EdgeInsets.zero {
didSet {
reload()
}
}

/// A UIColor.
public var color: UIColor? {
get {
return line?.backgroundColor
public class Divider: UIView {

fileprivate static func from(view: UIView) -> Divider? {
guard let divider = view.subviews.first(where: { $0 is Divider }) as? Divider else {
return nil
}

return divider
}
set(value) {
guard let v = value else {
line?.removeFromSuperview()
line = nil
return
}
if nil == line {
line = UIView()
line?.layer.zPosition = 5000
view?.addSubview(line!)
reload()
}
line?.backgroundColor = v

fileprivate static func orCreate(view: UIView) -> Divider {
if let divider = Divider.from(view: view) {
return divider
}

let divider = Divider()
view.addSubview(divider)

divider.update(thickness: 1)

return divider
}
}

/// A reference to the dividerAlignment.
public var alignment = DividerAlignment.bottom {
didSet {
reload()

private(set) var thickness: CGFloat = 1
public func update(thickness: CGFloat) {
guard let superview = self.superview else {
return
}

let c = contentEdgeInsets

self.removeFromSuperview()
superview.addSubview(self)
self.layer.zPosition = 5000

self.thickness = thickness

switch self.dividerAlignment {
case .bottom, .top:
superview.layout(self)
.leading(c.left, { _, _ in .equal })
.trailing(c.right, {_, _ in .equal })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #1236 to learn about layout relations. You can reduce this to .leading(c.left)

.height(thickness)

if case .bottom = self.dividerAlignment {
superview.layout(self).bottom(c.bottom, { _, _ in .equal })
} else {
superview.layout(self).top(c.top, { _, _ in .equal })
}

case .left, .right:
superview.layout(self)
.bottom(c.bottom, { _, _ in .equal })
.top(c.top, {_, _ in .equal })
.width(thickness)

if case .left = self.dividerAlignment {
superview.layout(self).leading(c.left, { _, _ in .equal })
} else {
superview.layout(self).trailing(c.right, { _, _ in .equal })
}
}
}
}

/**
Initializer that takes in a UIView.
- Parameter view: A UIView reference.
- Parameter thickness: A CGFloat value.
*/
internal init(view: UIView?, thickness: CGFloat = 1) {
self.view = view
self.thickness = thickness
}

/**
Hides the divier line.
*/
internal var isHidden = false {
didSet {
line?.isHidden = isHidden

public var alignment: DividerAlignment = .bottom {
didSet {
self.update(thickness: self.thickness)
}
}
}

/// Lays out the divider.
public func reload() {
guard let l = line, let v = view else {
return
/// A preset wrapper around contentEdgeInsets.
public var contentEdgeInsetsPreset = EdgeInsetsPreset.none {
didSet {
contentEdgeInsets = EdgeInsetsPresetToValue(preset: contentEdgeInsetsPreset)
}
}

let c = contentEdgeInsets
/// A reference to EdgeInsets.
public var contentEdgeInsets = EdgeInsets.zero {
didSet {
self.update(thickness: self.thickness)
}
}

switch alignment {
case .top:
l.frame = CGRect(x: c.left, y: c.top, width: v.bounds.width - c.left - c.right, height: thickness)
case .bottom:
l.frame = CGRect(x: c.left, y: v.bounds.height - thickness - c.bottom, width: v.bounds.width - c.left - c.right, height: thickness)
case .left:
l.frame = CGRect(x: c.left, y: c.top, width: thickness, height: v.bounds.height - c.top - c.bottom)
case .right:
l.frame = CGRect(x: v.bounds.width - thickness - c.right, y: c.top, width: thickness, height: v.bounds.height - c.top - c.bottom)
/// Lays out the divider.
public func reloadLayout() {
self.update(thickness: self.thickness)
}
}
}

/// A memory reference to the Divider instance.
fileprivate var DividerKey: UInt8 = 0

extension UIView {
/// TabBarItem reference.
public private(set) var divider: Divider {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems now instead of view.divider we need to do Divider.from(view: view). This is a radical API change

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally do not like the Divider.from(view: view) API change at all. Maybe we need to reconsider the entire divider on a UIView completely. @OrkhanAlikhanov @adamdahan

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup I agree with both of you @OrkhanAlikhanov @DanielDahan I like some of the refactoring done but overall the impact of this change is to large for existing users of Material.

get {
return AssociatedObject.get(base: self, key: &DividerKey) {
return Divider(view: self)
}
}
set(value) {
AssociatedObject.set(base: self, key: &DividerKey, value: value)
}
}

/// A preset wrapper around divider.contentEdgeInsets.
open var dividerContentEdgeInsetsPreset: EdgeInsetsPreset {
get {
return divider.contentEdgeInsetsPreset
}
set(value) {
divider.contentEdgeInsetsPreset = value
}
}

/// A reference to divider.contentEdgeInsets.
open var dividerContentEdgeInsets: EdgeInsets {
get {
return divider.contentEdgeInsets
}
set(value) {
divider.contentEdgeInsets = value
}
}

/// Divider color.
@IBInspectable
open var dividerColor: UIColor? {
get {
return divider.color
}
set(value) {
divider.color = value
public extension UIView {

/// A preset wrapper around divider.contentEdgeInsets.
open var dividerContentEdgeInsetsPreset: EdgeInsetsPreset {
get {
return Divider.from(view: self)?.contentEdgeInsetsPreset ?? .none
}
set(value) {
Divider.orCreate(view: self).contentEdgeInsetsPreset = value
}
}
}

/// Divider visibility.
@IBInspectable
open var isDividerHidden: Bool {
get {
return divider.isHidden

/// A reference to divider.contentEdgeInsets.
open var dividerContentEdgeInsets: EdgeInsets {
get {
return Divider.from(view: self)?.contentEdgeInsets ?? .zero
}
set(value) {
Divider.orCreate(view: self).contentEdgeInsets = value
}
}
set(value) {
divider.isHidden = value

/// Divider animation.
@IBInspectable
open var dividerAlignment: DividerAlignment {
get {
return Divider.from(view: self)?.alignment ?? .bottom
}

set {
Divider.orCreate(view: self).alignment = newValue
}
}
}

/// Divider animation.
open var dividerAlignment: DividerAlignment {
get {
return divider.alignment

/// Divider color.
@IBInspectable
open var dividerColor: UIColor? {
get {
return Divider.from(view: self)?.backgroundColor
}

set {
Divider.orCreate(view: self).backgroundColor = newValue
}
}
set(value) {
divider.alignment = value

/// Divider visibility.
@IBInspectable
open var isDividerHidden: Bool {
get {
return Divider.from(view: self) == nil
}

set {
if newValue {
Divider.from(view: self)?.isHidden = true
return
}

Divider.orCreate(view: self).isHidden = false
}
}
}

/// Divider thickness.
@IBInspectable
open var dividerThickness: CGFloat {
get {
return divider.thickness

/// Divider thickness.
@IBInspectable
open var dividerThickness: CGFloat {
get {
return Divider.from(view: self)?.thickness ?? 0.0
}

set {
guard newValue > 0 else {
Divider.from(view: self)?.isHidden = true
return
}

Divider.orCreate(view: self).update(thickness: newValue)
}
}
set(value) {
divider.thickness = value

/// Sets the divider frame.
public func layoutDivider() {
Divider.orCreate(view: self).reloadLayout()
}
}

/// Sets the divider frame.
open func layoutDivider() {
divider.reload()
}

}
Loading