first commit
This commit is contained in:
parent
29c9db4a94
commit
3d72669c73
70
.gitignore
vendored
Normal file
70
.gitignore
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
# Created by https://www.gitignore.io/api/swift
|
||||
|
||||
### Swift ###
|
||||
# Xcode
|
||||
#
|
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData/
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata/
|
||||
|
||||
## Other
|
||||
*.moved-aside
|
||||
*.xcuserstate
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.dSYM.zip
|
||||
*.dSYM
|
||||
|
||||
## Playgrounds
|
||||
timeline.xctimeline
|
||||
playground.xcworkspace
|
||||
|
||||
# Swift Package Manager
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||
# Packages/
|
||||
.build/
|
||||
|
||||
# CocoaPods
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
# Pods/
|
||||
|
||||
# Carthage
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||
# Carthage/Checkouts
|
||||
|
||||
Carthage/Build
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
|
||||
# End of https://www.gitignore.io/api/swift
|
||||
@ -16,6 +16,8 @@
|
||||
5282F0A3282270E000ADE765 /* ColorWheelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5282F0A2282270E000ADE765 /* ColorWheelTests.swift */; };
|
||||
5282F0AD282270E000ADE765 /* ColorWheelUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5282F0AC282270E000ADE765 /* ColorWheelUITests.swift */; };
|
||||
5282F0AF282270E000ADE765 /* ColorWheelUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5282F0AE282270E000ADE765 /* ColorWheelUITestsLaunchTests.swift */; };
|
||||
5282F0BC2822717E00ADE765 /* ColorWheelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5282F0BB2822717E00ADE765 /* ColorWheelView.swift */; };
|
||||
5282F0C028227A4A00ADE765 /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5282F0BF28227A4A00ADE765 /* ViewController.xib */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -49,6 +51,8 @@
|
||||
5282F0A8282270E000ADE765 /* ColorWheelUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ColorWheelUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5282F0AC282270E000ADE765 /* ColorWheelUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorWheelUITests.swift; sourceTree = "<group>"; };
|
||||
5282F0AE282270E000ADE765 /* ColorWheelUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorWheelUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||
5282F0BB2822717E00ADE765 /* ColorWheelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorWheelView.swift; sourceTree = "<group>"; };
|
||||
5282F0BF28227A4A00ADE765 /* ViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ViewController.xib; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -106,6 +110,8 @@
|
||||
5282F094282270E000ADE765 /* Assets.xcassets */,
|
||||
5282F096282270E000ADE765 /* LaunchScreen.storyboard */,
|
||||
5282F099282270E000ADE765 /* Info.plist */,
|
||||
5282F0BB2822717E00ADE765 /* ColorWheelView.swift */,
|
||||
5282F0BF28227A4A00ADE765 /* ViewController.xib */,
|
||||
);
|
||||
path = ColorWheel;
|
||||
sourceTree = "<group>";
|
||||
@ -233,6 +239,7 @@
|
||||
files = (
|
||||
5282F098282270E000ADE765 /* LaunchScreen.storyboard in Resources */,
|
||||
5282F095282270E000ADE765 /* Assets.xcassets in Resources */,
|
||||
5282F0C028227A4A00ADE765 /* ViewController.xib in Resources */,
|
||||
5282F093282270DE00ADE765 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -260,6 +267,7 @@
|
||||
files = (
|
||||
5282F090282270DE00ADE765 /* ViewController.swift in Sources */,
|
||||
5282F08C282270DE00ADE765 /* AppDelegate.swift in Sources */,
|
||||
5282F0BC2822717E00ADE765 /* ColorWheelView.swift in Sources */,
|
||||
5282F08E282270DE00ADE765 /* SceneDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -443,6 +451,7 @@
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -454,7 +463,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -471,6 +480,7 @@
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -482,7 +492,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
146
ColorWheel/ColorWheelView.swift
Normal file
146
ColorWheel/ColorWheelView.swift
Normal file
@ -0,0 +1,146 @@
|
||||
//
|
||||
// ColorWheelView.swift
|
||||
// ColorWheel
|
||||
//
|
||||
// Created by 楊昀羲 on 2019/3/8.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
// 建立 RGB 資料型別
|
||||
typealias RGB = (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
|
||||
|
||||
// 建立 HSV 資料型別
|
||||
typealias HSV = (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat)
|
||||
|
||||
class ColorWheelView: UIView {
|
||||
|
||||
// 邊距
|
||||
private let BORDER = 20.0
|
||||
|
||||
var wheelLayer: CALayer!
|
||||
|
||||
// 取得螢幕解析度縮放
|
||||
let scale: CGFloat = UIScreen.main.scale
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder);
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
// 色相-飽和度圓盤圖層
|
||||
let width = self.frame.width - (BORDER * 2.0)
|
||||
let height = self.frame.height - (BORDER * 2.0)
|
||||
|
||||
wheelLayer = CALayer()
|
||||
wheelLayer.frame = CGRect(x: BORDER, y: BORDER, width: width, height: height)
|
||||
wheelLayer.contents = createColorWheel(wheelLayer.frame.size)
|
||||
self.layer.addSublayer(wheelLayer)
|
||||
}
|
||||
|
||||
private func createColorWheel(_ size: CGSize) -> CGImage {
|
||||
// 建立色相-飽和度圓盤
|
||||
let originalWidth = size.width
|
||||
let originalHeight = size.height
|
||||
let dimension = min(originalWidth * scale, originalHeight * scale)
|
||||
let bufferLength = Int(dimension * dimension * 4) // 寬 * 高 * 色彩像素(RGBA)
|
||||
|
||||
// 建立點陣圖資料
|
||||
let bitmapData = CFDataCreateMutable(nil, 0)
|
||||
CFDataSetLength(bitmapData, CFIndex(bufferLength))
|
||||
let bitmap = CFDataGetMutableBytePtr(bitmapData)
|
||||
|
||||
// 塞入資料
|
||||
for y in stride(from: CGFloat(0), to: dimension, by: CGFloat(1)) {
|
||||
for x in stride(from: CGFloat(0), to: dimension, by: CGFloat(1)) {
|
||||
var hsv: HSV = (hue: 0, saturation: 0, brightness: 0, alpha: 0)
|
||||
var rgb: RGB = (red: 0, green: 0, blue: 0, alpha: 0)
|
||||
|
||||
let color = hueSaturationAtPoint(CGPoint(x: x, y: y))
|
||||
let hue = color.hue
|
||||
let saturation = color.saturation
|
||||
var a: CGFloat = 0.0
|
||||
if (saturation < 1.0) {
|
||||
// 將邊緣進行反鋸齒處理
|
||||
if (saturation > 0.99) {
|
||||
a = (1.0 - saturation) * 100
|
||||
} else {
|
||||
a = 1.0;
|
||||
}
|
||||
|
||||
hsv.hue = hue
|
||||
hsv.saturation = saturation
|
||||
hsv.brightness = 1.0
|
||||
hsv.alpha = a
|
||||
rgb = hsv2rgb(hsv)
|
||||
}
|
||||
let offset = Int(4 * (x + y * dimension))
|
||||
bitmap?[offset] = UInt8(rgb.red*255)
|
||||
bitmap?[offset + 1] = UInt8(rgb.green*255)
|
||||
bitmap?[offset + 2] = UInt8(rgb.blue*255)
|
||||
bitmap?[offset + 3] = UInt8(rgb.alpha*255)
|
||||
}
|
||||
}
|
||||
|
||||
// 將 bitmap 資料輸出到 CGImage
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let dataProvider = CGDataProvider(data: bitmapData!)
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo().rawValue | CGImageAlphaInfo.last.rawValue)
|
||||
let imageRef = CGImage(width: Int(dimension), height: Int(dimension), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: Int(dimension) * 4, space: colorSpace, bitmapInfo: bitmapInfo, provider: dataProvider!, decode: nil, shouldInterpolate: false, intent: CGColorRenderingIntent.defaultIntent)
|
||||
return imageRef!
|
||||
}
|
||||
|
||||
// 透過座標取得色相和飽和度
|
||||
func hueSaturationAtPoint(_ position: CGPoint) -> (hue: CGFloat, saturation: CGFloat) {
|
||||
let c = wheelLayer.frame.width * scale / 2
|
||||
let dx = CGFloat(position.x - c) / c
|
||||
let dy = CGFloat(position.y - c) / c
|
||||
let d = sqrt(CGFloat (dx * dx + dy * dy))
|
||||
|
||||
let saturation: CGFloat = d
|
||||
|
||||
var hue: CGFloat
|
||||
if (d == 0) {
|
||||
hue = 0;
|
||||
} else {
|
||||
hue = acos(dx/d) / CGFloat(Double.pi) / 2.0
|
||||
if (dy < 0) {
|
||||
hue = 1.0 - hue
|
||||
}
|
||||
}
|
||||
return (hue, saturation)
|
||||
}
|
||||
|
||||
// 將 HSV 轉換成 RGB
|
||||
func hsv2rgb(_ hsv: HSV) -> RGB {
|
||||
var rgb: RGB = (red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
|
||||
var r: CGFloat
|
||||
var g: CGFloat
|
||||
var b: CGFloat
|
||||
|
||||
let i = Int(hsv.hue * 6)
|
||||
let f = hsv.hue * 6 - CGFloat(i)
|
||||
let p = hsv.brightness * (1 - hsv.saturation)
|
||||
let q = hsv.brightness * (1 - f * hsv.saturation)
|
||||
let t = hsv.brightness * (1 - (1 - f) * hsv.saturation)
|
||||
switch (i % 6) {
|
||||
case 0: r = hsv.brightness; g = t; b = p; break;
|
||||
case 1: r = q; g = hsv.brightness; b = p; break;
|
||||
case 2: r = p; g = hsv.brightness; b = t; break;
|
||||
case 3: r = p; g = q; b = hsv.brightness; break;
|
||||
case 4: r = t; g = p; b = hsv.brightness; break;
|
||||
case 5: r = hsv.brightness; g = p; b = q; break;
|
||||
default: r = hsv.brightness; g = t; b = p;
|
||||
}
|
||||
|
||||
rgb.red = r
|
||||
rgb.green = g
|
||||
rgb.blue = b
|
||||
rgb.alpha = hsv.alpha
|
||||
return rgb
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,16 +2,23 @@
|
||||
// ViewController.swift
|
||||
// ColorWheel
|
||||
//
|
||||
// Created by 楊昀羲 on 2022/5/4.
|
||||
// Created by 楊昀羲 on 2019/3/8.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
var colorWheelView: ColorWheelView?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view.
|
||||
let size = self.view.frame.size.width
|
||||
let frame = CGRect(x: 0, y: 84, width: size, height: size)
|
||||
|
||||
colorWheelView = ColorWheelView(frame: frame)
|
||||
self.view.addSubview(colorWheelView!)
|
||||
}
|
||||
|
||||
|
||||
|
||||
18
ColorWheel/ViewController.xib
Normal file
18
ColorWheel/ViewController.xib
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
Loading…
Reference in New Issue
Block a user