first commit

This commit is contained in:
Raymond Yang 2022-05-05 12:02:50 +08:00
parent 29c9db4a94
commit 3d72669c73
5 changed files with 254 additions and 3 deletions

70
.gitignore vendored Normal file
View 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

View File

@ -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;
};

View 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
}
}

View File

@ -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!)
}

View 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>