Skip to content

Commit

Permalink
Merge branch 'release/0.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
afshin-hoseini committed Apr 24, 2019
2 parents e2757dd + a96576a commit b875a9a
Show file tree
Hide file tree
Showing 40 changed files with 1,559 additions and 30 deletions.
4 changes: 2 additions & 2 deletions LimberTabbar/LimberTabbar.podspec → LimberTabbar.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
Pod::Spec.new do |s|
s.name = 'LimberTabbar'
s.version = '0.1.0'
s.summary = 'A short description of LimberTabbar.'
s.summary = 'Yet another tabbar with smooth animation.'

# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
Expand All @@ -26,7 +26,7 @@ TODO: Add long description of the pod here.
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'afshin.hoseini@gmail.com' => 'afshin.hoseini@gmail.com' }
s.source = { :git => 'https://github.com/afshin.hoseini@gmail.com/LimberTabbar.git', :tag => s.version.to_s }
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
# s.social_media_url = 'https://twitter.com/hoseini_afshin'

s.ios.deployment_target = '8.0'

Expand Down
64 changes: 63 additions & 1 deletion LimberTabbar/LimberTabbar.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,31 @@
/* Begin PBXBuildFile section */
F4312C1C2259C9AE00EF67FC /* LimberTabbar.h in Headers */ = {isa = PBXBuildFile; fileRef = F4312C1A2259C9AE00EF67FC /* LimberTabbar.h */; settings = {ATTRIBUTES = (Public, ); }; };
F4312C432259D39300EF67FC /* CGMutablePath+pit.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4312C422259D39300EF67FC /* CGMutablePath+pit.swift */; };
F4312C472259E17100EF67FC /* AHPitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4312C462259E17100EF67FC /* AHPitView.swift */; };
F4312C49225A3AC700EF67FC /* AHLimberTabbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4312C48225A3AC700EF67FC /* AHLimberTabbar.swift */; };
F4312C4C225A4AEE00EF67FC /* ItemView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4312C4B225A4AEE00EF67FC /* ItemView.xib */; };
F4312C4F225A4D8100EF67FC /* AHLimberTabBarItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4312C4E225A4D8100EF67FC /* AHLimberTabBarItemView.swift */; };
F453D357226E043A006C0F71 /* AnimationConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = F453D356226E043A006C0F71 /* AnimationConfig.swift */; };
F49AD86F226F780A00E2AB24 /* AHLimberTabbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F49AD86E226F780A00E2AB24 /* AHLimberTabbarController.swift */; };
F4C65B522269F167007909F6 /* AHSelectedTabItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4C65B512269F167007909F6 /* AHSelectedTabItem.swift */; };
F4C65B54226B0946007909F6 /* AHLimberTabbarBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4C65B53226B0946007909F6 /* AHLimberTabbarBackgroundView.swift */; };
F4C65B56226CE247007909F6 /* AHLimberTabbarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4C65B55226CE247007909F6 /* AHLimberTabbarItem.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
F4312C172259C9AE00EF67FC /* LimberTabbar.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LimberTabbar.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F4312C1A2259C9AE00EF67FC /* LimberTabbar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LimberTabbar.h; sourceTree = "<group>"; };
F4312C1B2259C9AE00EF67FC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F4312C422259D39300EF67FC /* CGMutablePath+pit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGMutablePath+pit.swift"; sourceTree = "<group>"; };
F4312C462259E17100EF67FC /* AHPitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AHPitView.swift; sourceTree = "<group>"; };
F4312C48225A3AC700EF67FC /* AHLimberTabbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AHLimberTabbar.swift; sourceTree = "<group>"; };
F4312C4B225A4AEE00EF67FC /* ItemView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ItemView.xib; sourceTree = "<group>"; };
F4312C4E225A4D8100EF67FC /* AHLimberTabBarItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AHLimberTabBarItemView.swift; sourceTree = "<group>"; };
F453D356226E043A006C0F71 /* AnimationConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimationConfig.swift; sourceTree = "<group>"; };
F49AD86E226F780A00E2AB24 /* AHLimberTabbarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AHLimberTabbarController.swift; sourceTree = "<group>"; };
F4C65B512269F167007909F6 /* AHSelectedTabItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AHSelectedTabItem.swift; sourceTree = "<group>"; };
F4C65B53226B0946007909F6 /* AHLimberTabbarBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AHLimberTabbarBackgroundView.swift; sourceTree = "<group>"; };
F4C65B55226CE247007909F6 /* AHLimberTabbarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AHLimberTabbarItem.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -48,13 +66,46 @@
F4312C192259C9AE00EF67FC /* LimberTabbar */ = {
isa = PBXGroup;
children = (
F4312C4A225A4AAD00EF67FC /* Tabbar */,
F4312C452259E15A00EF67FC /* Extensions */,
F4312C1A2259C9AE00EF67FC /* LimberTabbar.h */,
F4312C1B2259C9AE00EF67FC /* Info.plist */,
F4312C422259D39300EF67FC /* CGMutablePath+pit.swift */,
F4312C462259E17100EF67FC /* AHPitView.swift */,
);
path = LimberTabbar;
sourceTree = "<group>";
};
F4312C452259E15A00EF67FC /* Extensions */ = {
isa = PBXGroup;
children = (
F4312C422259D39300EF67FC /* CGMutablePath+pit.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
F4312C4A225A4AAD00EF67FC /* Tabbar */ = {
isa = PBXGroup;
children = (
F4312C4D225A4D5E00EF67FC /* Item */,
F4312C48225A3AC700EF67FC /* AHLimberTabbar.swift */,
F4C65B512269F167007909F6 /* AHSelectedTabItem.swift */,
F4C65B53226B0946007909F6 /* AHLimberTabbarBackgroundView.swift */,
F453D356226E043A006C0F71 /* AnimationConfig.swift */,
F49AD86E226F780A00E2AB24 /* AHLimberTabbarController.swift */,
);
path = Tabbar;
sourceTree = "<group>";
};
F4312C4D225A4D5E00EF67FC /* Item */ = {
isa = PBXGroup;
children = (
F4312C4B225A4AEE00EF67FC /* ItemView.xib */,
F4312C4E225A4D8100EF67FC /* AHLimberTabBarItemView.swift */,
F4C65B55226CE247007909F6 /* AHLimberTabbarItem.swift */,
);
path = Item;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -124,6 +175,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F4312C4C225A4AEE00EF67FC /* ItemView.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -134,7 +186,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F4C65B54226B0946007909F6 /* AHLimberTabbarBackgroundView.swift in Sources */,
F4312C49225A3AC700EF67FC /* AHLimberTabbar.swift in Sources */,
F4C65B56226CE247007909F6 /* AHLimberTabbarItem.swift in Sources */,
F4312C472259E17100EF67FC /* AHPitView.swift in Sources */,
F4312C4F225A4D8100EF67FC /* AHLimberTabBarItemView.swift in Sources */,
F4312C432259D39300EF67FC /* CGMutablePath+pit.swift in Sources */,
F453D357226E043A006C0F71 /* AnimationConfig.swift in Sources */,
F4C65B522269F167007909F6 /* AHSelectedTabItem.swift in Sources */,
F49AD86F226F780A00E2AB24 /* AHLimberTabbarController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -276,6 +336,7 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = LimberTabbar/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -303,6 +364,7 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = LimberTabbar/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
133 changes: 133 additions & 0 deletions LimberTabbar/LimberTabbar/AHPitView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//
// UIPitView.swift
// LimberTabbar
//
// Created by Afshin Hoseini on 4/7/19.
// Copyright © 2019 Afshin Hoseini. All rights reserved.
//

import Foundation
import UIKit

@IBDesignable
public class AHPitView : UIView {

//MARK:- Properties
var borderLayer = CAShapeLayer()
var guideRectsLayer = CAShapeLayer()
let pitDepth = CGFloat(40)
let maxDepth = CGFloat(40)

@IBInspectable
public var pitPositionScale = CGFloat(0) {

didSet {

renderBorder()
}
}

@IBInspectable
public var pitDepthScale = CGFloat(0) {

didSet {

renderBorder()
}
}

@IBInspectable
public var showRects = true {

didSet {
renderBorder()
}
}

//MARK:- Initializers
public override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}

public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}

func commonInit() {

//Initializes border and guide rects layers

borderLayer.bounds = bounds
borderLayer.fillColor = UIColor.red.cgColor
borderLayer.strokeColor = UIColor.red.cgColor
borderLayer.position = CGPoint(x: 0, y: 0)
borderLayer.anchorPoint = CGPoint(x: 0, y: 0)
borderLayer.lineJoin = .round

borderLayer.shadowColor = UIColor.black.cgColor
borderLayer.shadowOffset = CGSize(width: 0, height: -2)
borderLayer.shadowRadius = 1
borderLayer.shadowOpacity = 0.3


guideRectsLayer.fillColor = nil
guideRectsLayer.strokeColor = UIColor.cyan.cgColor
guideRectsLayer.position = CGPoint(x: 0, y: 0)
guideRectsLayer.bounds = bounds
guideRectsLayer.anchorPoint = CGPoint(x: 0, y: 0)

layer.addSublayer(borderLayer)
layer.addSublayer(guideRectsLayer)

renderBorder()
self.backgroundColor = nil
}

//MARK:- Functions
public override func prepareForInterfaceBuilder() {

pitPositionScale = CGFloat(0.5)
pitDepthScale = CGFloat(1)
}

/**
* Renders the border of view including the hole
*/
func renderBorder() {

//Initial calculations
let pitWidth = CGMutablePath.calculatePitWith(maxPitDepth: pitDepth)
let y = CGFloat(0)
let possibleDiggingWidth = bounds.width - pitWidth
let holeStartingPointX = CGFloat(possibleDiggingWidth * pitPositionScale)

//Creates the hole
let borderPath = CGMutablePath()
borderPath.move(to: CGPoint.zero)
borderPath.addLine(to: CGPoint(x: holeStartingPointX, y: y))

let guideRects = borderPath.addPit(toPath: borderPath, startingPointX: holeStartingPointX, y: y, depth: pitDepth, scale: pitDepthScale).guideRects

borderPath.addLine(to: CGPoint(x: bounds.width, y: 0))
borderPath.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
borderPath.addLine(to: CGPoint(x: 0, y: bounds.height))
borderPath.addLine(to: CGPoint(x: 0, y: 0))

borderLayer.path = borderPath

//Rects layer

if (showRects) {

let rectPath = CGMutablePath()
rectPath.addRects(guideRects)
guideRectsLayer.path = rectPath
}
else {
guideRectsLayer.path = nil
}

}
}
9 changes: 0 additions & 9 deletions LimberTabbar/LimberTabbar/CGMutablePath+pit.swift

This file was deleted.

63 changes: 63 additions & 0 deletions LimberTabbar/LimberTabbar/Extensions/CGMutablePath+pit.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// CGMutablePath+pit.swift
// LimberTabbar
//
// Created by Afshin Hoseini on 4/7/19.
// Copyright © 2019 Afshin Hoseini. All rights reserved.
//

import Foundation
import UIKit

extension CGMutablePath {

class func calculatePitWith(maxPitDepth: CGFloat) -> CGFloat {

return maxPitDepth * 2.25
}

/**
Draws the pit's path from given starting point.
In order to simplify the code, the scale parameter has been used once for the middle rect's height calculation. The other discussed parameters have bound to middle rect's height.
**Returns** a tuple including guide rects and the end point.
*/
@discardableResult
public func addPit(toPath path: CGMutablePath, startingPointX : CGFloat, y: CGFloat, depth: CGFloat = 40, scale: CGFloat = 1) -> (guideRects: [CGRect], endPoint : CGPoint) {

let pitWidth = CGMutablePath.calculatePitWith(maxPitDepth: depth) // Including the pit's domains
let endPoint = CGPoint(x: startingPointX + pitWidth, y: y)

let centerRectWidth = depth
let centerRectHeight = depth * scale
let smallRectsWidth = centerRectWidth / 2
let smallRectsHeight = centerRectHeight / 2
let pitCenterBottomPoint = CGPoint(x: startingPointX + (pitWidth / 2), y: centerRectHeight)


let leftRect = CGRect(x: startingPointX, y: y, width: smallRectsWidth, height: smallRectsHeight)
let centerRect = CGRect(x: leftRect.origin.x + leftRect.width, y: y, width: centerRectWidth, height: centerRectHeight)
let rightRect = CGRect(x: centerRect.origin.x + centerRect.width, y: y, width: smallRectsWidth, height: smallRectsHeight)


//Curves' control points calculations.
//Right Curve's Top Control Point
let RCTCP = CGPoint(x: endPoint.x - (abs(rightRect.height) * 1.25), y: y)
//Right Curve's Bottom Control Point
let RCBCP = CGPoint(x: pitCenterBottomPoint.x + abs(centerRectHeight), y: centerRectHeight)
//Left Curve's Top Control Point
let LCTCP = CGPoint(x: startingPointX + (abs(leftRect.height) * 1.25), y: y)
//Left Curve's Bottom Control Point
let LCBCP = CGPoint(x: pitCenterBottomPoint.x - abs(centerRectHeight), y: centerRectHeight)



//Addes curves to the given path.

path.addCurve(to: pitCenterBottomPoint, control1: LCTCP, control2: LCBCP)
path.addCurve(to: endPoint, control1: RCBCP, control2: RCTCP)

return([leftRect, centerRect, rightRect], endPoint)
}
}
Loading

0 comments on commit b875a9a

Please sign in to comment.