init
This commit is contained in:
BIN
Example/SubModules/.DS_Store
vendored
Normal file
BIN
Example/SubModules/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
Example/SubModules/FUBeautyComponent/.DS_Store
vendored
Normal file
BIN
Example/SubModules/FUBeautyComponent/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "FUBeautyComponent"
|
||||
s.version = "1.0"
|
||||
s.license = 'MIT'
|
||||
s.summary = "Beauty component"
|
||||
s.description = "The beauty component of FULiveDemo."
|
||||
s.homepage = "https://github.com/Faceunity/FULiveDemo"
|
||||
s.author = { 'faceunity' => 'dev@faceunity.com' }
|
||||
s.platform = :ios, "12.0"
|
||||
s.source = { "http": "https://github.com/Faceunity/FULiveDemo"}
|
||||
s.source_files = '**/*.{h,m}'
|
||||
s.resources = 'FUBeautyComponent/Resource/**/*.{json}'
|
||||
s.requires_arc = true
|
||||
s.dependency 'FURenderKit'
|
||||
s.dependency 'FUCommonUIComponent'
|
||||
end
|
||||
@@ -0,0 +1,493 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 55;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
E30500B42891364700C9408B /* FUBeautySkinViewModel.h in Headers */ = {isa = PBXBuildFile; fileRef = E30500B22891364700C9408B /* FUBeautySkinViewModel.h */; };
|
||||
E30500B52891364700C9408B /* FUBeautySkinViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E30500B32891364700C9408B /* FUBeautySkinViewModel.m */; };
|
||||
E30500B82891365300C9408B /* FUBeautyShapeViewModel.h in Headers */ = {isa = PBXBuildFile; fileRef = E30500B62891365300C9408B /* FUBeautyShapeViewModel.h */; };
|
||||
E30500B92891365300C9408B /* FUBeautyShapeViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E30500B72891365300C9408B /* FUBeautyShapeViewModel.m */; };
|
||||
E32C6DCE2877DEDC008A9C08 /* FUBeautySkinModel.h in Headers */ = {isa = PBXBuildFile; fileRef = E32C6DCC2877DEDC008A9C08 /* FUBeautySkinModel.h */; };
|
||||
E32C6DCF2877DEDC008A9C08 /* FUBeautySkinModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E32C6DCD2877DEDC008A9C08 /* FUBeautySkinModel.m */; };
|
||||
E32C6DD22877DEEC008A9C08 /* FUBeautyShapeModel.h in Headers */ = {isa = PBXBuildFile; fileRef = E32C6DD02877DEEC008A9C08 /* FUBeautyShapeModel.h */; };
|
||||
E32C6DD32877DEEC008A9C08 /* FUBeautyShapeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E32C6DD12877DEEC008A9C08 /* FUBeautyShapeModel.m */; };
|
||||
E32C6DD62877E114008A9C08 /* FUBeautyShapeView.h in Headers */ = {isa = PBXBuildFile; fileRef = E32C6DD42877E114008A9C08 /* FUBeautyShapeView.h */; };
|
||||
E32C6DD72877E114008A9C08 /* FUBeautyShapeView.m in Sources */ = {isa = PBXBuildFile; fileRef = E32C6DD52877E114008A9C08 /* FUBeautyShapeView.m */; };
|
||||
E32D08E928758C5600884AE5 /* FUBeautyComponentManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E32D08E828758C5600884AE5 /* FUBeautyComponentManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E32D09192876CEF300884AE5 /* FUBeautyFilterViewModel.h in Headers */ = {isa = PBXBuildFile; fileRef = E32D09172876CEF300884AE5 /* FUBeautyFilterViewModel.h */; };
|
||||
E32D091A2876CEF300884AE5 /* FUBeautyFilterViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E32D09182876CEF300884AE5 /* FUBeautyFilterViewModel.m */; };
|
||||
E32D091D2876CF0F00884AE5 /* FUBeautyFilterModel.h in Headers */ = {isa = PBXBuildFile; fileRef = E32D091B2876CF0F00884AE5 /* FUBeautyFilterModel.h */; };
|
||||
E32D091E2876CF0F00884AE5 /* FUBeautyFilterModel.m in Sources */ = {isa = PBXBuildFile; fileRef = E32D091C2876CF0F00884AE5 /* FUBeautyFilterModel.m */; };
|
||||
E32D09222876CFDE00884AE5 /* beauty_filter.json in Resources */ = {isa = PBXBuildFile; fileRef = E32D09212876CFDE00884AE5 /* beauty_filter.json */; };
|
||||
E32D09242876D01C00884AE5 /* beauty_skin.json in Resources */ = {isa = PBXBuildFile; fileRef = E32D09232876D01C00884AE5 /* beauty_skin.json */; };
|
||||
E32D09262876D02E00884AE5 /* beauty_shape.json in Resources */ = {isa = PBXBuildFile; fileRef = E32D09252876D02E00884AE5 /* beauty_shape.json */; };
|
||||
E33834A12861772B0023482D /* FUBeautySkinView.h in Headers */ = {isa = PBXBuildFile; fileRef = E338349F2861772B0023482D /* FUBeautySkinView.h */; };
|
||||
E33834A22861772B0023482D /* FUBeautySkinView.m in Sources */ = {isa = PBXBuildFile; fileRef = E33834A02861772B0023482D /* FUBeautySkinView.m */; };
|
||||
E33834BA2861BE8C0023482D /* FUBeautyFilterView.h in Headers */ = {isa = PBXBuildFile; fileRef = E33834B82861BE8C0023482D /* FUBeautyFilterView.h */; };
|
||||
E33834BB2861BE8C0023482D /* FUBeautyFilterView.m in Sources */ = {isa = PBXBuildFile; fileRef = E33834B92861BE8C0023482D /* FUBeautyFilterView.m */; };
|
||||
E34C47EE285338080040093C /* FUBeautyComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = E34C47ED285338080040093C /* FUBeautyComponent.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E34C47FC2853381E0040093C /* FUBeautyDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = E34C47F52853381E0040093C /* FUBeautyDefine.h */; };
|
||||
E34C4831285347100040093C /* FUBeautyComponentManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E34C482F285347100040093C /* FUBeautyComponentManager.m */; };
|
||||
E3618FEC28583B9B00E7D8D2 /* FUBeautyDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = E3618FEB28583B9B00E7D8D2 /* FUBeautyDefine.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
E30500B22891364700C9408B /* FUBeautySkinViewModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautySkinViewModel.h; sourceTree = "<group>"; };
|
||||
E30500B32891364700C9408B /* FUBeautySkinViewModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautySkinViewModel.m; sourceTree = "<group>"; };
|
||||
E30500B62891365300C9408B /* FUBeautyShapeViewModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautyShapeViewModel.h; sourceTree = "<group>"; };
|
||||
E30500B72891365300C9408B /* FUBeautyShapeViewModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautyShapeViewModel.m; sourceTree = "<group>"; };
|
||||
E32C6DCC2877DEDC008A9C08 /* FUBeautySkinModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautySkinModel.h; sourceTree = "<group>"; };
|
||||
E32C6DCD2877DEDC008A9C08 /* FUBeautySkinModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautySkinModel.m; sourceTree = "<group>"; };
|
||||
E32C6DD02877DEEC008A9C08 /* FUBeautyShapeModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautyShapeModel.h; sourceTree = "<group>"; };
|
||||
E32C6DD12877DEEC008A9C08 /* FUBeautyShapeModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautyShapeModel.m; sourceTree = "<group>"; };
|
||||
E32C6DD42877E114008A9C08 /* FUBeautyShapeView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautyShapeView.h; sourceTree = "<group>"; };
|
||||
E32C6DD52877E114008A9C08 /* FUBeautyShapeView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautyShapeView.m; sourceTree = "<group>"; };
|
||||
E32D08E828758C5600884AE5 /* FUBeautyComponentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUBeautyComponentManager.h; sourceTree = "<group>"; };
|
||||
E32D09172876CEF300884AE5 /* FUBeautyFilterViewModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautyFilterViewModel.h; sourceTree = "<group>"; };
|
||||
E32D09182876CEF300884AE5 /* FUBeautyFilterViewModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautyFilterViewModel.m; sourceTree = "<group>"; };
|
||||
E32D091B2876CF0F00884AE5 /* FUBeautyFilterModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautyFilterModel.h; sourceTree = "<group>"; };
|
||||
E32D091C2876CF0F00884AE5 /* FUBeautyFilterModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautyFilterModel.m; sourceTree = "<group>"; };
|
||||
E32D09212876CFDE00884AE5 /* beauty_filter.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = beauty_filter.json; sourceTree = "<group>"; };
|
||||
E32D09232876D01C00884AE5 /* beauty_skin.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = beauty_skin.json; sourceTree = "<group>"; };
|
||||
E32D09252876D02E00884AE5 /* beauty_shape.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = beauty_shape.json; sourceTree = "<group>"; };
|
||||
E338349B286173C10023482D /* FUCommonUIComponent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FUCommonUIComponent.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E338349F2861772B0023482D /* FUBeautySkinView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautySkinView.h; sourceTree = "<group>"; };
|
||||
E33834A02861772B0023482D /* FUBeautySkinView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautySkinView.m; sourceTree = "<group>"; };
|
||||
E33834B82861BE8C0023482D /* FUBeautyFilterView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautyFilterView.h; sourceTree = "<group>"; };
|
||||
E33834B92861BE8C0023482D /* FUBeautyFilterView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautyFilterView.m; sourceTree = "<group>"; };
|
||||
E34C47EA285338080040093C /* FUBeautyComponent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FUBeautyComponent.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E34C47ED285338080040093C /* FUBeautyComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUBeautyComponent.h; sourceTree = "<group>"; };
|
||||
E34C47F52853381E0040093C /* FUBeautyDefine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUBeautyDefine.h; sourceTree = "<group>"; };
|
||||
E34C482F285347100040093C /* FUBeautyComponentManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautyComponentManager.m; sourceTree = "<group>"; };
|
||||
E3618FEB28583B9B00E7D8D2 /* FUBeautyDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUBeautyDefine.m; sourceTree = "<group>"; };
|
||||
E369F8CF28D851550036AC5A /* FURenderKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FURenderKit.framework; path = ../FULiveDemo/FURenderKit/FURenderKit.framework; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
E34C47E7285338080040093C /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
E338349A286173C10023482D /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E369F8CF28D851550036AC5A /* FURenderKit.framework */,
|
||||
E338349B286173C10023482D /* FUCommonUIComponent.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E34C47E0285338080040093C = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E34C47EC285338080040093C /* FUBeautyComponent */,
|
||||
E34C47EB285338080040093C /* Products */,
|
||||
E338349A286173C10023482D /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E34C47EB285338080040093C /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E34C47EA285338080040093C /* FUBeautyComponent.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E34C47EC285338080040093C /* FUBeautyComponent */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E34C47F42853381E0040093C /* Model */,
|
||||
E34C47F92853381E0040093C /* View */,
|
||||
E34C47F62853381E0040093C /* ViewModel */,
|
||||
E3A787302859AB0000FBDAFF /* Resource */,
|
||||
E34C47F52853381E0040093C /* FUBeautyDefine.h */,
|
||||
E3618FEB28583B9B00E7D8D2 /* FUBeautyDefine.m */,
|
||||
E32D08E828758C5600884AE5 /* FUBeautyComponentManager.h */,
|
||||
E34C482F285347100040093C /* FUBeautyComponentManager.m */,
|
||||
E34C47ED285338080040093C /* FUBeautyComponent.h */,
|
||||
);
|
||||
path = FUBeautyComponent;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E34C47F42853381E0040093C /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E32C6DCC2877DEDC008A9C08 /* FUBeautySkinModel.h */,
|
||||
E32C6DCD2877DEDC008A9C08 /* FUBeautySkinModel.m */,
|
||||
E32C6DD02877DEEC008A9C08 /* FUBeautyShapeModel.h */,
|
||||
E32C6DD12877DEEC008A9C08 /* FUBeautyShapeModel.m */,
|
||||
E32D091B2876CF0F00884AE5 /* FUBeautyFilterModel.h */,
|
||||
E32D091C2876CF0F00884AE5 /* FUBeautyFilterModel.m */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E34C47F62853381E0040093C /* ViewModel */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E30500B22891364700C9408B /* FUBeautySkinViewModel.h */,
|
||||
E30500B32891364700C9408B /* FUBeautySkinViewModel.m */,
|
||||
E30500B62891365300C9408B /* FUBeautyShapeViewModel.h */,
|
||||
E30500B72891365300C9408B /* FUBeautyShapeViewModel.m */,
|
||||
E32D09172876CEF300884AE5 /* FUBeautyFilterViewModel.h */,
|
||||
E32D09182876CEF300884AE5 /* FUBeautyFilterViewModel.m */,
|
||||
);
|
||||
path = ViewModel;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E34C47F92853381E0040093C /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E338349F2861772B0023482D /* FUBeautySkinView.h */,
|
||||
E33834A02861772B0023482D /* FUBeautySkinView.m */,
|
||||
E32C6DD42877E114008A9C08 /* FUBeautyShapeView.h */,
|
||||
E32C6DD52877E114008A9C08 /* FUBeautyShapeView.m */,
|
||||
E33834B82861BE8C0023482D /* FUBeautyFilterView.h */,
|
||||
E33834B92861BE8C0023482D /* FUBeautyFilterView.m */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E3A787302859AB0000FBDAFF /* Resource */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E32D09232876D01C00884AE5 /* beauty_skin.json */,
|
||||
E32D09252876D02E00884AE5 /* beauty_shape.json */,
|
||||
E32D09212876CFDE00884AE5 /* beauty_filter.json */,
|
||||
);
|
||||
path = Resource;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
E34C47E5285338080040093C /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E30500B82891365300C9408B /* FUBeautyShapeViewModel.h in Headers */,
|
||||
E30500B42891364700C9408B /* FUBeautySkinViewModel.h in Headers */,
|
||||
E32D08E928758C5600884AE5 /* FUBeautyComponentManager.h in Headers */,
|
||||
E32C6DD22877DEEC008A9C08 /* FUBeautyShapeModel.h in Headers */,
|
||||
E32C6DCE2877DEDC008A9C08 /* FUBeautySkinModel.h in Headers */,
|
||||
E32C6DD62877E114008A9C08 /* FUBeautyShapeView.h in Headers */,
|
||||
E33834BA2861BE8C0023482D /* FUBeautyFilterView.h in Headers */,
|
||||
E32D09192876CEF300884AE5 /* FUBeautyFilterViewModel.h in Headers */,
|
||||
E33834A12861772B0023482D /* FUBeautySkinView.h in Headers */,
|
||||
E34C47FC2853381E0040093C /* FUBeautyDefine.h in Headers */,
|
||||
E32D091D2876CF0F00884AE5 /* FUBeautyFilterModel.h in Headers */,
|
||||
E34C47EE285338080040093C /* FUBeautyComponent.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
E34C47E9285338080040093C /* FUBeautyComponent */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = E34C47F1285338080040093C /* Build configuration list for PBXNativeTarget "FUBeautyComponent" */;
|
||||
buildPhases = (
|
||||
E34C47E5285338080040093C /* Headers */,
|
||||
E34C47E6285338080040093C /* Sources */,
|
||||
E34C47E7285338080040093C /* Frameworks */,
|
||||
E34C47E8285338080040093C /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = FUBeautyComponent;
|
||||
productName = FUBeautyComponent;
|
||||
productReference = E34C47EA285338080040093C /* FUBeautyComponent.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
E34C47E1285338080040093C /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastUpgradeCheck = 1330;
|
||||
TargetAttributes = {
|
||||
E34C47E9285338080040093C = {
|
||||
CreatedOnToolsVersion = 13.3.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = E34C47E4285338080040093C /* Build configuration list for PBXProject "FUBeautyComponent" */;
|
||||
compatibilityVersion = "Xcode 13.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
"zh-Hans",
|
||||
Base,
|
||||
);
|
||||
mainGroup = E34C47E0285338080040093C;
|
||||
productRefGroup = E34C47EB285338080040093C /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
E34C47E9285338080040093C /* FUBeautyComponent */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
E34C47E8285338080040093C /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E32D09242876D01C00884AE5 /* beauty_skin.json in Resources */,
|
||||
E32D09222876CFDE00884AE5 /* beauty_filter.json in Resources */,
|
||||
E32D09262876D02E00884AE5 /* beauty_shape.json in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
E34C47E6285338080040093C /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E34C4831285347100040093C /* FUBeautyComponentManager.m in Sources */,
|
||||
E32C6DD32877DEEC008A9C08 /* FUBeautyShapeModel.m in Sources */,
|
||||
E33834A22861772B0023482D /* FUBeautySkinView.m in Sources */,
|
||||
E32D091A2876CEF300884AE5 /* FUBeautyFilterViewModel.m in Sources */,
|
||||
E32D091E2876CF0F00884AE5 /* FUBeautyFilterModel.m in Sources */,
|
||||
E30500B92891365300C9408B /* FUBeautyShapeViewModel.m in Sources */,
|
||||
E30500B52891364700C9408B /* FUBeautySkinViewModel.m in Sources */,
|
||||
E33834BB2861BE8C0023482D /* FUBeautyFilterView.m in Sources */,
|
||||
E32C6DCF2877DEDC008A9C08 /* FUBeautySkinModel.m in Sources */,
|
||||
E32C6DD72877E114008A9C08 /* FUBeautyShapeView.m in Sources */,
|
||||
E3618FEC28583B9B00E7D8D2 /* FUBeautyDefine.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
E34C47EF285338080040093C /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.4;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
E34C47F0285338080040093C /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
E34C47F2285338080040093C /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 35A6KD62ZJ;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../FULiveDemo/FURenderKit",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = faceunity.FUBeautyComponent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
E34C47F3285338080040093C /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 35A6KD62ZJ;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../FULiveDemo/FURenderKit",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = faceunity.FUBeautyComponent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
E34C47E4285338080040093C /* Build configuration list for PBXProject "FUBeautyComponent" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
E34C47EF285338080040093C /* Debug */,
|
||||
E34C47F0285338080040093C /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
E34C47F1285338080040093C /* Build configuration list for PBXNativeTarget "FUBeautyComponent" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
E34C47F2285338080040093C /* Debug */,
|
||||
E34C47F3285338080040093C /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = E34C47E1285338080040093C /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1330"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E34C47E9285338080040093C"
|
||||
BuildableName = "FUBeautyComponent.framework"
|
||||
BlueprintName = "FUBeautyComponent"
|
||||
ReferencedContainer = "container:FUBeautyComponent.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E34C47E9285338080040093C"
|
||||
BuildableName = "FUBeautyComponent.framework"
|
||||
BlueprintName = "FUBeautyComponent"
|
||||
ReferencedContainer = "container:FUBeautyComponent.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
BIN
Example/SubModules/FUBeautyComponent/FUBeautyComponent/.DS_Store
vendored
Normal file
BIN
Example/SubModules/FUBeautyComponent/FUBeautyComponent/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// FUBeautyComponent.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/10.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUBeautyComponentManager.h"
|
||||
|
||||
//! Project version number for FUBeautyComponent.
|
||||
FOUNDATION_EXPORT double FUBeautyComponentVersionNumber;
|
||||
|
||||
//! Project version string for FUBeautyComponent.
|
||||
FOUNDATION_EXPORT const unsigned char FUBeautyComponentVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <FUBeautyComponent/PublicHeader.h>
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// FUBeautyComponentManager.h
|
||||
// FUBeautyComponentManager
|
||||
//
|
||||
// Created by 项林平 on 2022/6/10.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol FUBeautyComponentDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
- (void)beautyComponentViewHeightDidChange:(CGFloat)height;
|
||||
|
||||
- (void)beautyComponentDidTouchDownComparison;
|
||||
|
||||
- (void)beautyComponentDidTouchUpComparison;
|
||||
/// 提示
|
||||
- (void)beautyComponentNeedsDisplayPromptContent:(NSString *)content;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeautyComponentManager : NSObject
|
||||
|
||||
@property (nonatomic, weak) id<FUBeautyComponentDelegate> delegate;
|
||||
/// 美颜视图总高度
|
||||
@property (nonatomic, assign, readonly) CGFloat componentViewHeight;
|
||||
/// 美颜视图选中功能索引,默认-1,-1表示未选中
|
||||
@property (nonatomic, assign, readonly) NSInteger selectedIndex;
|
||||
|
||||
@property (nonatomic, weak, readonly) UIView *targetView;
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
/// 销毁
|
||||
+ (void)destory;
|
||||
|
||||
/// 在目标视图中添加美颜组件视图(固定位置为目标视图底部)
|
||||
/// @param view 目标视图
|
||||
- (void)addComponentViewToView:(UIView *)view;
|
||||
|
||||
/// 在父视图中移除美颜组件视图
|
||||
- (void)removeComponentView;
|
||||
|
||||
//设置所有效果为上次数据
|
||||
- (void)beautyStyleSetAllDefaultValues;
|
||||
|
||||
@property (nonatomic, assign)BOOL enableRender;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,329 @@
|
||||
//
|
||||
// FUBeautyComponentManager.m
|
||||
// FUBeautyComponentManager
|
||||
//
|
||||
// Created by 项林平 on 2022/6/10.
|
||||
//
|
||||
|
||||
#import "FUBeautyComponentManager.h"
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
#import "FUBeautySkinView.h"
|
||||
#import "FUBeautyShapeView.h"
|
||||
#import "FUBeautyFilterView.h"
|
||||
|
||||
#import <FUCommonUIComponent/FUCommonUIComponent.h>
|
||||
#import <FURenderKit/FURenderKit.h>
|
||||
|
||||
static FUBeautyComponentManager *beautyComponentManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
@interface FUBeautyComponentManager ()<FUSegmentBarDelegate, FUBeautyFilterViewDelegate>
|
||||
|
||||
@property (nonatomic, weak) UIView *targetView;
|
||||
|
||||
@property (nonatomic, strong) FUSegmentBar *categoryView;
|
||||
@property (nonatomic, strong) UIButton *compareButton;
|
||||
|
||||
@property (nonatomic, strong) FUBeautySkinView *beautySkinView;
|
||||
@property (nonatomic, strong) FUBeautyShapeView *beautyShapeView;
|
||||
@property (nonatomic, strong) FUBeautyFilterView *beautyFilterView;
|
||||
|
||||
@property (nonatomic, strong) FUBeautySkinViewModel *beautySkinViewModel;
|
||||
@property (nonatomic, strong) FUBeautyShapeViewModel *beautyShapeViewModel;
|
||||
@property (nonatomic, strong) FUBeautyFilterViewModel *beautyFilterViewModel;
|
||||
|
||||
@property (nonatomic, assign) NSInteger selectedIndex;
|
||||
@property (nonatomic, strong) UIControl *control;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautyComponentManager
|
||||
|
||||
#pragma mark - Class methods
|
||||
|
||||
+ (instancetype)sharedManager {
|
||||
dispatch_once(&onceToken, ^{
|
||||
beautyComponentManager = [[FUBeautyComponentManager alloc] init];
|
||||
beautyComponentManager.enableRender = true;
|
||||
});
|
||||
return beautyComponentManager;
|
||||
}
|
||||
|
||||
+ (void)destory {
|
||||
onceToken = 0;
|
||||
beautyComponentManager = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.selectedIndex = FUBeautyCategoryNone;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Instance methods
|
||||
|
||||
- (void)addComponentViewToView:(UIView *)view {
|
||||
NSAssert(view != nil, @"FUBeautyComponent: view can not be nil!");
|
||||
self.targetView = view;
|
||||
// [self removeComponentView];
|
||||
self.control.frame = view.bounds;
|
||||
[self.targetView addSubview:self.control];
|
||||
// [self.targetView addSubview:self.compareButton];
|
||||
[self.targetView addSubview:self.beautySkinView];
|
||||
[self.targetView addSubview:self.beautyShapeView];
|
||||
[self.targetView addSubview:self.beautyFilterView];
|
||||
[self.targetView addSubview:self.categoryView];
|
||||
if (self.categoryView.selectedIndex < 0) {
|
||||
[self.categoryView selectItemAtIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeComponentView {
|
||||
[self.control removeFromSuperview];
|
||||
// if (self.compareButton.superview) {
|
||||
// [self.compareButton removeFromSuperview];
|
||||
// }
|
||||
if (self.beautySkinView.superview) {
|
||||
[self.beautySkinView removeFromSuperview];
|
||||
}
|
||||
if (self.beautyShapeView.superview) {
|
||||
[self.beautyShapeView removeFromSuperview];
|
||||
}
|
||||
if (self.beautyFilterView.superview) {
|
||||
[self.beautyFilterView removeFromSuperview];
|
||||
}
|
||||
if (self.categoryView.superview) {
|
||||
[self.categoryView removeFromSuperview];
|
||||
}
|
||||
_targetView = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Private methods
|
||||
|
||||
- (void)controlClick {
|
||||
[self removeComponentView];
|
||||
}
|
||||
|
||||
- (void)showEffectView:(UIView *)view animated:(BOOL)animated completion:(void (^)(void))completion {
|
||||
view.hidden = NO;
|
||||
self.compareButton.hidden = NO;
|
||||
if (animated) {
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
view.transform = CGAffineTransformMakeTranslation(0, -CGRectGetHeight(view.frame));
|
||||
self.compareButton.transform = CGAffineTransformMakeTranslation(0, -CGRectGetHeight(view.frame));
|
||||
} completion:^(BOOL finished) {
|
||||
!completion ?: completion();
|
||||
}];
|
||||
} else {
|
||||
view.transform = CGAffineTransformMakeTranslation(0, -CGRectGetHeight(view.frame));
|
||||
self.compareButton.transform = CGAffineTransformMakeTranslation(0, -CGRectGetHeight(view.frame));
|
||||
!completion ?: completion();
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(beautyComponentViewHeightDidChange:)]) {
|
||||
[self.delegate beautyComponentViewHeightDidChange:CGRectGetHeight(view.frame) + CGRectGetHeight(self.categoryView.frame)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hideEffectView:(UIView *)view animated:(BOOL)animated completion:(void (^)(void))completion {
|
||||
if (animated) {
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
view.transform = CGAffineTransformIdentity;
|
||||
} completion:^(BOOL finished) {
|
||||
view.hidden = YES;
|
||||
!completion ?: completion();
|
||||
}];
|
||||
} else {
|
||||
view.transform = CGAffineTransformIdentity;
|
||||
view.hidden = YES;
|
||||
!completion ?: completion();
|
||||
}
|
||||
}
|
||||
|
||||
- (UIView *)showingView {
|
||||
UIView *view;
|
||||
switch (self.selectedIndex) {
|
||||
case FUBeautyCategorySkin:{
|
||||
view = self.beautySkinView;
|
||||
}
|
||||
break;
|
||||
case FUBeautyCategoryShape:{
|
||||
view = self.beautyShapeView;
|
||||
}
|
||||
break;
|
||||
case FUBeautyCategoryFilter:{
|
||||
view = self.beautyFilterView;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
#pragma mark - Event response
|
||||
|
||||
- (void)compareTouchDownAction {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(beautyComponentDidTouchDownComparison)]) {
|
||||
[self.delegate beautyComponentDidTouchDownComparison];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)compareTouchUpAction {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(beautyComponentDidTouchUpComparison)]) {
|
||||
[self.delegate beautyComponentDidTouchUpComparison];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - FUSegmentBarDelegate
|
||||
|
||||
- (void)segmentBar:(FUSegmentBar *)segmentBar didSelectItemAtIndex:(NSUInteger)index {
|
||||
if(index == 3) {
|
||||
self.enableRender = !self.enableRender;
|
||||
[self hideEffectView:[self showingView] animated:YES completion:^{
|
||||
segmentBar.userInteractionEnabled = YES;
|
||||
}];
|
||||
if (self.enableRender) {
|
||||
[self.categoryView selectItemAtIndex:0];
|
||||
}
|
||||
else {
|
||||
self.selectedIndex = index;
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(beautyComponentViewHeightDidChange:)]) {
|
||||
[self.delegate beautyComponentViewHeightDidChange:CGRectGetHeight(self.categoryView.frame)];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (index == self.selectedIndex) {
|
||||
// 隐藏
|
||||
segmentBar.userInteractionEnabled = NO;
|
||||
[self hideEffectView:[self showingView] animated:YES completion:^{
|
||||
segmentBar.userInteractionEnabled = YES;
|
||||
}];
|
||||
self.compareButton.transform = CGAffineTransformIdentity;
|
||||
self.compareButton.hidden = YES;
|
||||
[segmentBar selectItemAtIndex:-1];
|
||||
self.selectedIndex = FUBeautyCategoryNone;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(beautyComponentViewHeightDidChange:)]) {
|
||||
[self.delegate beautyComponentViewHeightDidChange:CGRectGetHeight(self.categoryView.frame)];
|
||||
}
|
||||
} else {
|
||||
segmentBar.userInteractionEnabled = NO;
|
||||
if (self.selectedIndex > FUBeautyCategoryNone) {
|
||||
[self hideEffectView:[self showingView] animated:NO completion:nil];
|
||||
}
|
||||
self.selectedIndex = index;
|
||||
[self showEffectView:[self showingView] animated:YES completion:^{
|
||||
segmentBar.userInteractionEnabled = YES;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - FUBeautyFilterViewDelegate
|
||||
|
||||
- (void)beautyFilterViewDidChangeFilter:(NSString *)name {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(beautyComponentNeedsDisplayPromptContent:)]) {
|
||||
[self.delegate beautyComponentNeedsDisplayPromptContent:name];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)beautyStyleSetAllDefaultValues {
|
||||
// 恢复美肤、美型、滤镜效果
|
||||
[self.beautySkinViewModel setAllSkinValues];
|
||||
[self.beautyShapeViewModel setAllShapeValues];
|
||||
[self.beautyFilterViewModel setCurrentFilter];
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (FUSegmentBar *)categoryView {
|
||||
if (!_categoryView) {
|
||||
NSArray<NSString *> *categories = @[FUBeautyStringWithKey(@"skin"), FUBeautyStringWithKey(@"shape"), FUBeautyStringWithKey(@"filter")];
|
||||
FUSegmentBarConfigurations *configurations = [[FUSegmentBarConfigurations alloc] init];
|
||||
configurations.titleFont = [UIFont systemFontOfSize:15];
|
||||
_categoryView = [[FUSegmentBar alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(self.targetView.bounds) - FUBeautyHeightIncludeBottomSafeArea(FUBeautyCategoryViewHeight), CGRectGetWidth(self.targetView.bounds), FUBeautyHeightIncludeBottomSafeArea(FUBeautyCategoryViewHeight)) titles:categories configuration:configurations];
|
||||
_categoryView.delegate = self;
|
||||
}
|
||||
return _categoryView;
|
||||
}
|
||||
|
||||
//- (UIButton *)compareButton {
|
||||
// if (!_compareButton) {
|
||||
// _compareButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
// _compareButton.frame = CGRectMake(15, CGRectGetMinY(self.categoryView.frame) - 54, 44, 44);
|
||||
// [_compareButton setImage:[UIImage imageNamed:@"compare_item"] forState:UIControlStateNormal];
|
||||
// [_compareButton addTarget:self action:@selector(compareTouchDownAction) forControlEvents:UIControlEventTouchDown];
|
||||
// [_compareButton addTarget:self action:@selector(compareTouchUpAction) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
|
||||
// _compareButton.hidden = YES;
|
||||
// }
|
||||
// return _compareButton;
|
||||
//}
|
||||
|
||||
- (FUBeautySkinView *)beautySkinView {
|
||||
if (!_beautySkinView) {
|
||||
_beautySkinView = [[FUBeautySkinView alloc] initWithFrame:CGRectMake(0, CGRectGetMinY(self.categoryView.frame), CGRectGetWidth(self.targetView.bounds), FUBeautyFunctionViewOverallHeight) viewModel:self.beautySkinViewModel];
|
||||
_beautySkinView.hidden = YES;
|
||||
}
|
||||
return _beautySkinView;
|
||||
}
|
||||
|
||||
- (FUBeautyShapeView *)beautyShapeView {
|
||||
if (!_beautyShapeView) {
|
||||
_beautyShapeView = [[FUBeautyShapeView alloc] initWithFrame:CGRectMake(0, CGRectGetMinY(self.categoryView.frame), CGRectGetWidth(self.targetView.bounds), FUBeautyFunctionViewOverallHeight) viewModel:self.beautyShapeViewModel];
|
||||
_beautyShapeView.hidden = YES;
|
||||
}
|
||||
return _beautyShapeView;
|
||||
}
|
||||
|
||||
- (FUBeautyFilterView *)beautyFilterView {
|
||||
if (!_beautyFilterView) {
|
||||
_beautyFilterView = [[FUBeautyFilterView alloc] initWithFrame:CGRectMake(0, CGRectGetMinY(self.categoryView.frame), CGRectGetWidth(self.targetView.bounds), FUBeautyFunctionViewOverallHeight) viewModel:self.beautyFilterViewModel];
|
||||
_beautyFilterView.hidden = YES;
|
||||
_beautyFilterView.delegate = self;
|
||||
}
|
||||
return _beautyFilterView;
|
||||
}
|
||||
|
||||
- (FUBeautySkinViewModel *)beautySkinViewModel {
|
||||
if (!_beautySkinViewModel) {
|
||||
_beautySkinViewModel = [[FUBeautySkinViewModel alloc] init];
|
||||
}
|
||||
return _beautySkinViewModel;
|
||||
}
|
||||
|
||||
- (FUBeautyShapeViewModel *)beautyShapeViewModel {
|
||||
if (!_beautyShapeViewModel) {
|
||||
_beautyShapeViewModel = [[FUBeautyShapeViewModel alloc] init];
|
||||
}
|
||||
return _beautyShapeViewModel;
|
||||
}
|
||||
|
||||
- (FUBeautyFilterViewModel *)beautyFilterViewModel {
|
||||
if (!_beautyFilterViewModel) {
|
||||
_beautyFilterViewModel = [[FUBeautyFilterViewModel alloc] init];
|
||||
}
|
||||
return _beautyFilterViewModel;
|
||||
}
|
||||
|
||||
- (CGFloat)componentViewHeight {
|
||||
if (self.selectedIndex == FUBeautyCategoryNone) {
|
||||
return FUBeautyHeightIncludeBottomSafeArea(FUBeautyCategoryViewHeight);
|
||||
} else {
|
||||
return FUBeautyHeightIncludeBottomSafeArea(FUBeautyCategoryViewHeight) + FUBeautyFunctionViewOverallHeight;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIControl *)control {
|
||||
if (!_control) {
|
||||
_control = [[UIControl alloc] init];
|
||||
_control.backgroundColor = [UIColor colorWithWhite:0 alpha:0.1];
|
||||
[_control addTarget:self action:@selector(controlClick) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _control;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// FUBeautyDefine.h
|
||||
// FUBeautyUIComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/9.
|
||||
//
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#ifndef FUBeautyDefine_h
|
||||
#define FUBeautyDefine_h
|
||||
|
||||
|
||||
#define FUBeautyStringWithKey(aKey) NSLocalizedString(aKey, nil)
|
||||
|
||||
#pragma mark - Const
|
||||
|
||||
extern const CGFloat FUBeautyCategoryViewHeight;
|
||||
|
||||
extern const CGFloat FUBeautyFunctionViewOverallHeight;
|
||||
|
||||
extern const CGFloat FUBeautyFunctionSliderHeight;
|
||||
|
||||
extern NSString * const FUPersistentBeautySkinKey;
|
||||
|
||||
extern NSString * const FUPersistentBeautyShapeKey;
|
||||
|
||||
extern NSString * const FUPersistentBeautyFilterKey;
|
||||
|
||||
extern NSString * const FUPersistentBeautySelectedFilterIndexKey;
|
||||
|
||||
|
||||
#pragma mark - Enum
|
||||
|
||||
typedef NS_ENUM(NSInteger, FUBeautyCategory) {
|
||||
FUBeautyCategoryNone = -1,
|
||||
FUBeautyCategorySkin = 0, //美肤
|
||||
FUBeautyCategoryShape = 1, //美型
|
||||
FUBeautyCategoryFilter = 2 //滤镜
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FUBeautySkin) {
|
||||
FUBeautySkinBlurLevel = 0,
|
||||
FUBeautySkinColorLevel,
|
||||
FUBeautySkinRedLevel,
|
||||
FUBeautySkinSharpen,
|
||||
FUBeautySkinFaceThreed,
|
||||
FUBeautySkinEyeBright,
|
||||
FUBeautySkinToothWhiten,
|
||||
FUBeautySkinRemovePouchStrength,
|
||||
FUBeautySkinRemoveNasolabialFoldsStrength
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FUBeautyShape) {
|
||||
FUBeautyShapeCheekThinning = 0,
|
||||
FUBeautyShapeCheekV,
|
||||
FUBeautyShapeCheekNarrow,
|
||||
FUBeautyShapeCheekShort,
|
||||
FUBeautyShapeCheekSmall,
|
||||
FUBeautyShapeCheekbones,
|
||||
FUBeautyShapeLowerJaw,
|
||||
FUBeautyShapeEyeEnlarging,
|
||||
FUBeautyShapeEyeCircle,
|
||||
FUBeautyShapeChin,
|
||||
FUBeautyShapeForehead,
|
||||
FUBeautyShapeNose,
|
||||
FUBeautyShapeMouth,
|
||||
FUBeautyShapeLipThick,
|
||||
FUBeautyShapeEyeHeight,
|
||||
FUBeautyShapeCanthus,
|
||||
FUBeautyShapeEyeLid,
|
||||
FUBeautyShapeEyeSpace,
|
||||
FUBeautyShapeEyeRotate,
|
||||
FUBeautyShapeLongNose,
|
||||
FUBeautyShapePhiltrum,
|
||||
FUBeautyShapeSmile,
|
||||
FUBeautyShapeBrowHeight,
|
||||
FUBeautyShapeBrowSpace,
|
||||
FUBeautyShapeBrowThick
|
||||
};
|
||||
|
||||
#pragma mark - Inline methods
|
||||
|
||||
static inline CGFloat FUBeautyHeightIncludeBottomSafeArea(CGFloat height) {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
height += [UIApplication sharedApplication].delegate.window.safeAreaInsets.bottom;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
static inline UIImage * FUBeautyImageNamed(NSString *name) {
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:@"FUBeautyComponent" ofType:@"framework" inDirectory:@"Frameworks"];
|
||||
NSBundle *bundle = [NSBundle bundleWithPath:path];
|
||||
return [UIImage imageNamed:name inBundle:bundle compatibleWithTraitCollection:nil];;
|
||||
}
|
||||
|
||||
#endif /* FUBeautyDefine_h */
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// FUBeautyDefine.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/14.
|
||||
//
|
||||
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
const CGFloat FUBeautyCategoryViewHeight = 49.f;
|
||||
|
||||
const CGFloat FUBeautyFunctionViewOverallHeight = 141.f;
|
||||
|
||||
const CGFloat FUBeautyFunctionSliderHeight = 30.f;
|
||||
|
||||
NSString * const FUPersistentBeautySkinKey = @"FUPersistentBeautySkin";
|
||||
|
||||
NSString * const FUPersistentBeautyShapeKey = @"FUPersistentBeautyShape";
|
||||
|
||||
NSString * const FUPersistentBeautyFilterKey = @"FUPersistentBeautyFilter";
|
||||
|
||||
NSString * const FUPersistentBeautySelectedFilterIndexKey = @"FUPersistentBeautySelectedFilterIndex";
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// FUBeautyFilterModel.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/7.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBeautyFilterModel : NSObject
|
||||
|
||||
@property (nonatomic, assign) NSInteger filterIndex;
|
||||
@property (nonatomic, copy) NSString *filterName;
|
||||
@property (nonatomic, assign) double filterLevel;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// FUBeautyFilterModel.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/7.
|
||||
//
|
||||
|
||||
#import "FUBeautyFilterModel.h"
|
||||
|
||||
@implementation FUBeautyFilterModel
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// FUBeautyShapeModel.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/8.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBeautyShapeModel : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *name;
|
||||
/// 美型类型
|
||||
@property (nonatomic, assign) FUBeautyShape type;
|
||||
/// 当前值
|
||||
@property (nonatomic) double currentValue;
|
||||
/// 默认值
|
||||
@property (nonatomic) double defaultValue;
|
||||
/// 默认值是否中位数
|
||||
@property (nonatomic, assign) BOOL defaultValueInMiddle;
|
||||
/// 是否区分设备性能
|
||||
@property (nonatomic, assign) BOOL differentiateDevicePerformance;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// FUBeautyShapeModel.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/8.
|
||||
//
|
||||
|
||||
#import "FUBeautyShapeModel.h"
|
||||
|
||||
@implementation FUBeautyShapeModel
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// FUBeautySkinModel.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/8.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBeautySkinModel : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *name;
|
||||
/// 美肤类型
|
||||
@property (nonatomic, assign) FUBeautySkin type;
|
||||
/// 当前值
|
||||
@property (nonatomic, assign) double currentValue;
|
||||
/// 默认值
|
||||
@property (nonatomic, assign) double defaultValue;
|
||||
/// 默认值是否中位数
|
||||
@property (nonatomic, assign) BOOL defaultValueInMiddle;
|
||||
/// 实际值对应0.0-1.0的倍率
|
||||
@property (nonatomic, assign) NSInteger ratio;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// FUBeautySkinModel.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/8.
|
||||
//
|
||||
|
||||
#import "FUBeautySkinModel.h"
|
||||
|
||||
@implementation FUBeautySkinModel
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,322 @@
|
||||
[
|
||||
{
|
||||
"filterIndex":0,
|
||||
"filterName":"origin",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":1,
|
||||
"filterName":"ziran1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":2,
|
||||
"filterName":"ziran2",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":3,
|
||||
"filterName":"ziran3",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":4,
|
||||
"filterName":"ziran4",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":5,
|
||||
"filterName":"ziran5",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":6,
|
||||
"filterName":"ziran6",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":7,
|
||||
"filterName":"ziran7",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":8,
|
||||
"filterName":"ziran8",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":9,
|
||||
"filterName":"zhiganhui1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":10,
|
||||
"filterName":"zhiganhui2",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":11,
|
||||
"filterName":"zhiganhui3",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":12,
|
||||
"filterName":"zhiganhui4",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":13,
|
||||
"filterName":"zhiganhui5",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":14,
|
||||
"filterName":"zhiganhui6",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":15,
|
||||
"filterName":"zhiganhui7",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":16,
|
||||
"filterName":"zhiganhui8",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":17,
|
||||
"filterName":"mitao1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":18,
|
||||
"filterName":"mitao2",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":19,
|
||||
"filterName":"mitao3",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":20,
|
||||
"filterName":"mitao4",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":21,
|
||||
"filterName":"mitao5",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":22,
|
||||
"filterName":"mitao6",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":23,
|
||||
"filterName":"mitao7",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":24,
|
||||
"filterName":"mitao8",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":25,
|
||||
"filterName":"bailiang1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":26,
|
||||
"filterName":"bailiang2",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":27,
|
||||
"filterName":"bailiang3",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":28,
|
||||
"filterName":"bailiang4",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":29,
|
||||
"filterName":"bailiang5",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":30,
|
||||
"filterName":"bailiang6",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":31,
|
||||
"filterName":"bailiang7",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":32,
|
||||
"filterName":"fennen1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":33,
|
||||
"filterName":"fennen2",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":34,
|
||||
"filterName":"fennen3",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":35,
|
||||
"filterName":"fennen5",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":36,
|
||||
"filterName":"fennen6",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":37,
|
||||
"filterName":"fennen7",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":38,
|
||||
"filterName":"fennen8",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":39,
|
||||
"filterName":"lengsediao1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":40,
|
||||
"filterName":"lengsediao2",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":41,
|
||||
"filterName":"lengsediao3",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":42,
|
||||
"filterName":"lengsediao4",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":43,
|
||||
"filterName":"lengsediao7",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":44,
|
||||
"filterName":"lengsediao8",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":45,
|
||||
"filterName":"lengsediao11",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":46,
|
||||
"filterName":"nuansediao1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":47,
|
||||
"filterName":"nuansediao2",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":48,
|
||||
"filterName":"gexing1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":49,
|
||||
"filterName":"gexing2",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":50,
|
||||
"filterName":"gexing3",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":51,
|
||||
"filterName":"gexing4",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":52,
|
||||
"filterName":"gexing5",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":53,
|
||||
"filterName":"gexing7",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":54,
|
||||
"filterName":"gexing10",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":55,
|
||||
"filterName":"gexing11",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":56,
|
||||
"filterName":"xiaoqingxin1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":57,
|
||||
"filterName":"xiaoqingxin3",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":58,
|
||||
"filterName":"xiaoqingxin4",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":59,
|
||||
"filterName":"xiaoqingxin6",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":60,
|
||||
"filterName":"heibai1",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":61,
|
||||
"filterName":"heibai2",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":62,
|
||||
"filterName":"heibai3",
|
||||
"filterLevel":0.4
|
||||
},
|
||||
{
|
||||
"filterIndex":63,
|
||||
"filterName":"heibai4",
|
||||
"filterLevel":0.4
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,202 @@
|
||||
[
|
||||
{
|
||||
"name":"瘦脸",
|
||||
"type":0,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"v脸",
|
||||
"type":1,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"窄脸",
|
||||
"type":2,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"短脸",
|
||||
"type":3,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"小脸",
|
||||
"type":4,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"瘦颧骨",
|
||||
"type":5,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"瘦下颌骨",
|
||||
"type":6,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"大眼",
|
||||
"type":7,
|
||||
"currentValue":0.4,
|
||||
"defaultValue":0.4,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"圆眼",
|
||||
"type":8,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"下巴",
|
||||
"type":9,
|
||||
"currentValue":0.3,
|
||||
"defaultValue":0.3,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"额头",
|
||||
"type":10,
|
||||
"currentValue":0.3,
|
||||
"defaultValue":0.3,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"瘦鼻",
|
||||
"type":11,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"嘴型",
|
||||
"type":12,
|
||||
"currentValue":0.4,
|
||||
"defaultValue":0.4,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"嘴唇厚度",
|
||||
"type":13,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":true
|
||||
},
|
||||
{
|
||||
"name":"眼睛位置",
|
||||
"type":14,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":true
|
||||
},
|
||||
{
|
||||
"name":"开眼角",
|
||||
"type":15,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"眼睑下至",
|
||||
"type":16,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":true
|
||||
},
|
||||
{
|
||||
"name":"眼距",
|
||||
"type":17,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"眼睛角度",
|
||||
"type":18,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"长鼻",
|
||||
"type":19,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"缩人中",
|
||||
"type":20,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"微笑嘴角",
|
||||
"type":21,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"differentiateDevicePerformance":false
|
||||
},
|
||||
{
|
||||
"name":"眉毛上下",
|
||||
"type":22,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":true
|
||||
},
|
||||
{
|
||||
"name":"眉间距",
|
||||
"type":23,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":true
|
||||
},
|
||||
{
|
||||
"name":"眉毛粗细",
|
||||
"type":24,
|
||||
"currentValue":0.5,
|
||||
"defaultValue":0.5,
|
||||
"defaultValueInMiddle":true,
|
||||
"differentiateDevicePerformance":true
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,74 @@
|
||||
[
|
||||
{
|
||||
"name":"磨皮",
|
||||
"type":0,
|
||||
"currentValue":2,
|
||||
"defaultValue":2,
|
||||
"defaultValueInMiddle":false,
|
||||
"ratio":6
|
||||
},
|
||||
{
|
||||
"name":"美白",
|
||||
"type":1,
|
||||
"currentValue":0.3,
|
||||
"defaultValue":0.3,
|
||||
"defaultValueInMiddle":false,
|
||||
"ratio":1
|
||||
},
|
||||
{
|
||||
"name":"红润",
|
||||
"type":2,
|
||||
"currentValue":0.3,
|
||||
"defaultValue":0.3,
|
||||
"defaultValueInMiddle":false,
|
||||
"ratio":1
|
||||
},
|
||||
{
|
||||
"name":"锐化",
|
||||
"type":3,
|
||||
"currentValue":0.2,
|
||||
"defaultValue":0.2,
|
||||
"defaultValueInMiddle":false,
|
||||
"ratio":1
|
||||
},
|
||||
{
|
||||
"name":"五官立体",
|
||||
"type":4,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"ratio":1
|
||||
},
|
||||
{
|
||||
"name":"亮眼",
|
||||
"type":5,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"ratio":1
|
||||
},
|
||||
{
|
||||
"name":"美牙",
|
||||
"type":6,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"ratio":1
|
||||
},
|
||||
{
|
||||
"name":"去黑眼圈",
|
||||
"type":7,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"ratio":1
|
||||
},
|
||||
{
|
||||
"name":"去法令纹",
|
||||
"type":8,
|
||||
"currentValue":0.0,
|
||||
"defaultValue":0.0,
|
||||
"defaultValueInMiddle":false,
|
||||
"ratio":1
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// FUBeautyFilterView.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/21.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "FUBeautyFilterViewModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol FUBeautyFilterViewDelegate <NSObject>
|
||||
|
||||
/// 滤镜变化
|
||||
- (void)beautyFilterViewDidChangeFilter:(NSString *)name;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeautyFilterView : UIView
|
||||
|
||||
@property (nonatomic, weak) id<FUBeautyFilterViewDelegate> delegate;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame viewModel:(FUBeautyFilterViewModel *)viewModel;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeautyFilterCell : UICollectionViewCell
|
||||
|
||||
@property (nonatomic, strong, readonly) UIImageView *imageView;
|
||||
@property (nonatomic, strong, readonly) UILabel *textLabel;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,201 @@
|
||||
//
|
||||
// FUBeautyFilterView.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/21.
|
||||
//
|
||||
|
||||
#import "FUBeautyFilterView.h"
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
#import <FUCommonUIComponent/FUSlider.h>
|
||||
|
||||
static NSString * const kFUBeautyFilterCellIdentifier = @"FUBeautyFilterCell";
|
||||
|
||||
@interface FUBeautyFilterView ()<UICollectionViewDataSource, UICollectionViewDelegate>
|
||||
|
||||
@property (nonatomic, strong) FUSlider *filterSlider;
|
||||
|
||||
@property (nonatomic, strong) UICollectionView *filterCollectionView;
|
||||
|
||||
@property (nonatomic, strong) FUBeautyFilterViewModel *viewModel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautyFilterView
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
return [self initWithFrame:frame viewModel:[[FUBeautyFilterViewModel alloc] init]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame viewModel:(FUBeautyFilterViewModel *)viewModel {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.viewModel = viewModel;
|
||||
[self configureUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - UI
|
||||
|
||||
- (void)configureUI {
|
||||
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
|
||||
UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
|
||||
effectView.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
|
||||
[self addSubview:effectView];
|
||||
|
||||
[self addSubview:self.filterSlider];
|
||||
[self addSubview:self.filterCollectionView];
|
||||
NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:self.filterCollectionView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
|
||||
NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:self.filterCollectionView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
|
||||
NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:self.filterCollectionView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
|
||||
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:self.filterCollectionView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:98];
|
||||
[self addConstraints:@[bottom, leading, trailing]];
|
||||
[self.filterCollectionView addConstraint:height];
|
||||
// 默认选中
|
||||
[self.filterCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:self.viewModel.selectedIndex inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
self.filterSlider.hidden = self.viewModel.selectedIndex < 1;
|
||||
if (!self.filterSlider.hidden) {
|
||||
self.filterSlider.value = self.viewModel.beautyFilters[self.viewModel.selectedIndex].filterLevel;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Event response
|
||||
|
||||
- (void)sliderValueChanged {
|
||||
[self.viewModel setFilterValue:self.filterSlider.value];
|
||||
}
|
||||
|
||||
#pragma mark - Collection view data source
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.viewModel.beautyFilters.count;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FUBeautyFilterCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kFUBeautyFilterCellIdentifier forIndexPath:indexPath];
|
||||
FUBeautyFilterModel *filter = self.viewModel.beautyFilters[indexPath.item];
|
||||
cell.imageView.image = [UIImage imageNamed:filter.filterName];
|
||||
cell.textLabel.text = FUBeautyStringWithKey(filter.filterName);
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Collection view delegate
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (self.viewModel.selectedIndex == indexPath.item) {
|
||||
return;
|
||||
}
|
||||
self.filterSlider.hidden = indexPath.item < 1;
|
||||
if (!self.filterSlider.hidden) {
|
||||
self.filterSlider.value = self.viewModel.beautyFilters[indexPath.item].filterLevel;
|
||||
}
|
||||
self.viewModel.selectedIndex = indexPath.item;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(beautyFilterViewDidChangeFilter:)]) {
|
||||
[self.delegate beautyFilterViewDidChangeFilter:FUBeautyStringWithKey(self.viewModel.beautyFilters[indexPath.item].filterName)];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (FUSlider *)filterSlider {
|
||||
if (!_filterSlider) {
|
||||
_filterSlider = [[FUSlider alloc] initWithFrame:CGRectMake(56, 16, CGRectGetWidth(self.frame) - 112, 30)];
|
||||
_filterSlider.bidirection = NO;
|
||||
_filterSlider.hidden = YES;
|
||||
[_filterSlider addTarget:self action:@selector(sliderValueChanged) forControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
return _filterSlider;
|
||||
}
|
||||
|
||||
- (UICollectionView *)filterCollectionView {
|
||||
if (!_filterCollectionView) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
layout.itemSize = CGSizeMake(54, 70);
|
||||
layout.minimumLineSpacing = 16;
|
||||
layout.minimumInteritemSpacing = 50;
|
||||
layout.sectionInset = UIEdgeInsetsMake(16, 18, 10, 18);
|
||||
_filterCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_filterCollectionView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_filterCollectionView.backgroundColor = [UIColor clearColor];
|
||||
_filterCollectionView.showsHorizontalScrollIndicator = NO;
|
||||
_filterCollectionView.dataSource = self;
|
||||
_filterCollectionView.delegate = self;
|
||||
[_filterCollectionView registerClass:[FUBeautyFilterCell class] forCellWithReuseIdentifier:kFUBeautyFilterCellIdentifier];
|
||||
}
|
||||
return _filterCollectionView;
|
||||
}
|
||||
|
||||
- (FUBeautyFilterViewModel *)viewModel {
|
||||
if (!_viewModel) {
|
||||
_viewModel = [[FUBeautyFilterViewModel alloc] init];
|
||||
}
|
||||
return _viewModel;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeautyFilterCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *imageView;
|
||||
@property (nonatomic, strong) UILabel *textLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautyFilterCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self.contentView addSubview:self.imageView];
|
||||
NSLayoutConstraint *imageTop = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1 constant:0];
|
||||
NSLayoutConstraint *imageLeading = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
|
||||
NSLayoutConstraint *imageTrailing = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
|
||||
NSLayoutConstraint *imageHeight = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
|
||||
[self.contentView addConstraints:@[imageTop, imageLeading, imageTrailing]];
|
||||
[self.imageView addConstraint:imageHeight];
|
||||
|
||||
[self.contentView addSubview:self.textLabel];
|
||||
NSLayoutConstraint *textTop = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeBottom multiplier:1 constant:2];
|
||||
NSLayoutConstraint *textLeading = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
|
||||
NSLayoutConstraint *textTrailing = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
|
||||
[self.contentView addConstraints:@[textTop, textLeading, textTrailing]];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected {
|
||||
[super setSelected:selected];
|
||||
self.imageView.layer.borderWidth = selected ? 2 : 0;
|
||||
self.imageView.layer.borderColor = selected ? [UIColor colorWithRed:103/255.0 green:195/255.0 blue:103/255.0 alpha:1].CGColor : [UIColor clearColor].CGColor;
|
||||
self.textLabel.textColor = selected ? [UIColor colorWithRed:103/255.0 green:195/255.0 blue:103/255.0 alpha:1] : [UIColor whiteColor];
|
||||
}
|
||||
|
||||
- (UIImageView *)imageView {
|
||||
if (!_imageView) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_imageView.layer.masksToBounds = YES;
|
||||
_imageView.layer.cornerRadius = 3.f;
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (UILabel *)textLabel {
|
||||
if (!_textLabel) {
|
||||
_textLabel = [[UILabel alloc] init];
|
||||
_textLabel.textColor = [UIColor whiteColor];
|
||||
_textLabel.font = [UIFont systemFontOfSize:14];
|
||||
_textLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_textLabel.adjustsFontSizeToFitWidth = YES;
|
||||
_textLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
}
|
||||
return _textLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// FUBeautyShapeView.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/8.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "FUBeautyShapeViewModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBeautyShapeView : UIView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame viewModel:(FUBeautyShapeViewModel *)viewModel;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeautyShapeCell : UICollectionViewCell
|
||||
|
||||
@property (nonatomic, strong, readonly) UIImageView *imageView;
|
||||
|
||||
@property (nonatomic, strong, readonly) UILabel *textLabel;
|
||||
/// 是否允许选择
|
||||
@property (nonatomic, assign) BOOL disabled;
|
||||
|
||||
@property (nonatomic, assign) BOOL defaultInMiddle;
|
||||
|
||||
@property (nonatomic, assign) double currentValue;
|
||||
|
||||
@property (nonatomic, assign) double defaultValue;
|
||||
|
||||
@property (nonatomic, copy) NSString *imageName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,299 @@
|
||||
//
|
||||
// FUBeautyShapeView.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/8.
|
||||
//
|
||||
|
||||
#import "FUBeautyShapeView.h"
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
#import <FUCommonUIComponent/FUCommonUIComponent.h>
|
||||
|
||||
static NSString * const kFUBeautyShapeCellIdentifier = @"FUBeautyShapeCell";
|
||||
|
||||
@interface FUBeautyShapeView ()<UICollectionViewDataSource, UICollectionViewDelegate>
|
||||
|
||||
@property (nonatomic, strong) UICollectionView *shapeCollectionView;
|
||||
/// 程度调节
|
||||
@property (nonatomic, strong) FUSlider *slider;
|
||||
/// 恢复按钮
|
||||
@property (nonatomic, strong) FUSquareButton *recoverButton;
|
||||
|
||||
@property (nonatomic, strong) FUBeautyShapeViewModel *viewModel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautyShapeView
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
return [self initWithFrame:frame viewModel:[[FUBeautyShapeViewModel alloc] init]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame viewModel:(FUBeautyShapeViewModel *)viewModel {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.viewModel = viewModel;
|
||||
[self configureUI];
|
||||
[self refreshSubviews];
|
||||
[self collectionView:self.shapeCollectionView didSelectItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - UI
|
||||
|
||||
- (void)configureUI {
|
||||
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
|
||||
UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
|
||||
effectView.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
|
||||
[self addSubview:effectView];
|
||||
|
||||
[self addSubview:self.slider];
|
||||
[self addSubview:self.recoverButton];
|
||||
NSLayoutConstraint *recoverLeadingConstraint = [NSLayoutConstraint constraintWithItem:self.recoverButton attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1 constant:17];
|
||||
NSLayoutConstraint *recoverBottomConstraint = [NSLayoutConstraint constraintWithItem:self.recoverButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:-6];
|
||||
NSLayoutConstraint *recoverWidthConstraint = [NSLayoutConstraint constraintWithItem:self.recoverButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:44];
|
||||
NSLayoutConstraint *recoverHeightConstraint = [NSLayoutConstraint constraintWithItem:self.recoverButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:74];
|
||||
|
||||
[self addConstraints:@[recoverLeadingConstraint, recoverBottomConstraint]];
|
||||
[self.recoverButton addConstraints:@[recoverWidthConstraint, recoverHeightConstraint]];
|
||||
|
||||
// 分割线
|
||||
UIView *verticalLine = [[UIView alloc] init];
|
||||
verticalLine.backgroundColor = [UIColor colorWithRed:229/255.f green:229/255.f blue:229/255.f alpha:0.2];
|
||||
verticalLine.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self addSubview:verticalLine];
|
||||
NSLayoutConstraint *lineLeadingConstraint = [NSLayoutConstraint constraintWithItem:verticalLine attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.recoverButton attribute:NSLayoutAttributeTrailing multiplier:1 constant:14];
|
||||
NSLayoutConstraint *lineCenterYConstraint = [NSLayoutConstraint constraintWithItem:verticalLine attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.recoverButton attribute:NSLayoutAttributeCenterY multiplier:1 constant:-15];
|
||||
NSLayoutConstraint *lineWidthConstraint = [NSLayoutConstraint constraintWithItem:verticalLine attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:1];
|
||||
NSLayoutConstraint *lineHeightConstraint = [NSLayoutConstraint constraintWithItem:verticalLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:24];
|
||||
[self addConstraints:@[lineLeadingConstraint, lineCenterYConstraint]];
|
||||
[verticalLine addConstraints:@[lineWidthConstraint, lineHeightConstraint]];
|
||||
|
||||
[self addSubview:self.shapeCollectionView];
|
||||
NSLayoutConstraint *collectionLeadingConstraint = [NSLayoutConstraint constraintWithItem:self.shapeCollectionView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1 constant:76];
|
||||
NSLayoutConstraint *collectionTrailingConstraint = [NSLayoutConstraint constraintWithItem:self.shapeCollectionView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
|
||||
NSLayoutConstraint *collectionBottomConstraint = [NSLayoutConstraint constraintWithItem:self.shapeCollectionView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
|
||||
NSLayoutConstraint *collectionHeightConstraint = [NSLayoutConstraint constraintWithItem:self.shapeCollectionView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:98];
|
||||
[self addConstraints:@[collectionLeadingConstraint, collectionTrailingConstraint, collectionBottomConstraint]];
|
||||
[self.shapeCollectionView addConstraint:collectionHeightConstraint];
|
||||
}
|
||||
|
||||
- (void)refreshSubviews {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (self.viewModel.isDefaultValue) {
|
||||
self.recoverButton.alpha = 0.6;
|
||||
self.recoverButton.userInteractionEnabled = NO;
|
||||
} else {
|
||||
self.recoverButton.alpha = 1;
|
||||
self.recoverButton.userInteractionEnabled = YES;
|
||||
}
|
||||
if (!self.slider.hidden && self.viewModel.selectedIndex >= 0) {
|
||||
self.slider.bidirection = self.viewModel.beautyShapes[self.viewModel.selectedIndex].defaultValueInMiddle;
|
||||
self.slider.value = self.viewModel.beautyShapes[self.viewModel.selectedIndex].currentValue;
|
||||
}
|
||||
[self.shapeCollectionView reloadData];
|
||||
if (self.viewModel.selectedIndex >= 0) {
|
||||
[self.shapeCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:self.viewModel.selectedIndex inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Event response
|
||||
|
||||
- (void)recoverAction {
|
||||
[FUAlertManager showAlertWithTitle:nil message:FUBeautyStringWithKey(@"是否将所有参数恢复到默认值") cancel:FUBeautyStringWithKey(@"取消") confirm:FUBeautyStringWithKey(@"确定") inController:nil confirmHandler:^{
|
||||
[self.viewModel recoverAllShapeValuesToDefault];
|
||||
[self refreshSubviews];
|
||||
} cancelHandler:nil];
|
||||
}
|
||||
|
||||
- (void)sliderValueChanged {
|
||||
[self.viewModel setShapeValue:self.slider.value];
|
||||
}
|
||||
|
||||
- (void)sliderChangeEnded {
|
||||
[self refreshSubviews];
|
||||
}
|
||||
|
||||
#pragma mark - Collection view data source
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.viewModel.beautyShapes.count;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FUBeautyShapeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kFUBeautyShapeCellIdentifier forIndexPath:indexPath];
|
||||
FUBeautyShapeModel *shape = self.viewModel.beautyShapes[indexPath.item];
|
||||
cell.textLabel.text = FUBeautyStringWithKey(shape.name);
|
||||
cell.imageName = shape.name;
|
||||
cell.defaultInMiddle = shape.defaultValueInMiddle;
|
||||
cell.defaultValue = shape.defaultValue;
|
||||
cell.currentValue = shape.currentValue;
|
||||
// 处理低性能手机禁用特效
|
||||
if (shape.differentiateDevicePerformance) {
|
||||
cell.disabled = self.viewModel.performanceLevel != FUDevicePerformanceLevelHigh;
|
||||
} else {
|
||||
cell.disabled = NO;
|
||||
}
|
||||
cell.selected = indexPath.item == self.viewModel.selectedIndex;
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Collection view delegate
|
||||
|
||||
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FUBeautyShapeModel *shape = self.viewModel.beautyShapes[indexPath.item];
|
||||
if (shape.differentiateDevicePerformance) {
|
||||
if (self.viewModel.performanceLevel != FUDevicePerformanceLevelHigh) {
|
||||
[FUTipHUD showTips:[NSString stringWithFormat:FUBeautyStringWithKey(@"该功能只支持在高端机上使用"), FUBeautyStringWithKey(shape.name)] dismissWithDelay:1];
|
||||
[self.shapeCollectionView reloadData];
|
||||
if (self.viewModel.selectedIndex >= 0) {
|
||||
[self.shapeCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:self.viewModel.selectedIndex inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (indexPath.item == self.viewModel.selectedIndex) {
|
||||
return;
|
||||
}
|
||||
self.viewModel.selectedIndex = indexPath.item;
|
||||
FUBeautyShapeModel *shape = self.viewModel.beautyShapes[indexPath.item];
|
||||
if (self.slider.hidden) {
|
||||
self.slider.hidden = NO;
|
||||
}
|
||||
self.slider.bidirection = shape.defaultValueInMiddle;
|
||||
self.slider.value = shape.currentValue;
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UICollectionView *)shapeCollectionView {
|
||||
if (!_shapeCollectionView) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
layout.itemSize = CGSizeMake(44, 74);
|
||||
layout.minimumLineSpacing = 22;
|
||||
layout.minimumInteritemSpacing = 22;
|
||||
layout.sectionInset = UIEdgeInsetsMake(16, 16, 6, 16);
|
||||
_shapeCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_shapeCollectionView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_shapeCollectionView.backgroundColor = [UIColor clearColor];
|
||||
_shapeCollectionView.showsVerticalScrollIndicator = NO;
|
||||
_shapeCollectionView.showsHorizontalScrollIndicator = NO;
|
||||
_shapeCollectionView.dataSource = self;
|
||||
_shapeCollectionView.delegate = self;
|
||||
[_shapeCollectionView registerClass:[FUBeautyShapeCell class] forCellWithReuseIdentifier:kFUBeautyShapeCellIdentifier];
|
||||
}
|
||||
return _shapeCollectionView;
|
||||
}
|
||||
|
||||
- (FUSquareButton *)recoverButton {
|
||||
if (!_recoverButton) {
|
||||
_recoverButton = [[FUSquareButton alloc] initWithFrame:CGRectMake(0, 0, 44, 74)];
|
||||
[_recoverButton setTitle:FUBeautyStringWithKey(@"恢复") forState:UIControlStateNormal];
|
||||
[_recoverButton setImage:[UIImage imageNamed:@"recover_item"] forState:UIControlStateNormal];
|
||||
_recoverButton.alpha = 0.6;
|
||||
_recoverButton.userInteractionEnabled = NO;
|
||||
[_recoverButton addTarget:self action:@selector(recoverAction) forControlEvents:UIControlEventTouchUpInside];
|
||||
_recoverButton.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
}
|
||||
return _recoverButton;
|
||||
}
|
||||
|
||||
-(FUSlider *)slider {
|
||||
if (!_slider) {
|
||||
_slider = [[FUSlider alloc] initWithFrame:CGRectMake(56, 16, CGRectGetWidth(self.frame) - 116, FUBeautyFunctionSliderHeight)];
|
||||
_slider.hidden = YES;
|
||||
[_slider addTarget:self action:@selector(sliderValueChanged) forControlEvents:UIControlEventValueChanged];
|
||||
[_slider addTarget:self action:@selector(sliderChangeEnded) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
|
||||
}
|
||||
return _slider;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeautyShapeCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *imageView;
|
||||
|
||||
@property (nonatomic, strong) UILabel *textLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautyShapeCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self.contentView addSubview:self.imageView];
|
||||
NSLayoutConstraint *imageTop = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1 constant:0];
|
||||
NSLayoutConstraint *imageLeading = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
|
||||
NSLayoutConstraint *imageTrailing = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
|
||||
NSLayoutConstraint *imageHeight = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
|
||||
[self.contentView addConstraints:@[imageTop, imageLeading, imageTrailing]];
|
||||
[self.imageView addConstraint:imageHeight];
|
||||
|
||||
[self.contentView addSubview:self.textLabel];
|
||||
NSLayoutConstraint *textTop = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeBottom multiplier:1 constant:7];
|
||||
NSLayoutConstraint *textLeading = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
|
||||
NSLayoutConstraint *textTrailing = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
|
||||
[self.contentView addConstraints:@[textTop, textLeading, textTrailing]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected {
|
||||
[super setSelected:selected];
|
||||
if (self.disabled) {
|
||||
self.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-0", self.imageName]];
|
||||
self.imageView.alpha = 0.7;
|
||||
self.textLabel.alpha = 0.7;
|
||||
} else {
|
||||
self.imageView.alpha = 1;
|
||||
self.textLabel.alpha = 1;
|
||||
BOOL changed = NO;
|
||||
if (self.defaultInMiddle) {
|
||||
changed = fabs(self.currentValue - 0.5) > 0.01;
|
||||
}else{
|
||||
changed = self.currentValue > 0.01;
|
||||
}
|
||||
if (selected) {
|
||||
self.imageView.image = changed ? [UIImage imageNamed:[NSString stringWithFormat:@"%@-3", self.imageName]] : [UIImage imageNamed:[NSString stringWithFormat:@"%@-2", self.imageName]];
|
||||
self.textLabel.textColor = [UIColor colorWithRed:103/255.f green:195/255.f blue:103/255.f alpha:1];
|
||||
} else {
|
||||
self.imageView.image = changed ? [UIImage imageNamed:[NSString stringWithFormat:@"%@-1", self.imageName]] : [UIImage imageNamed:[NSString stringWithFormat:@"%@-0", self.imageName]];
|
||||
self.textLabel.textColor = [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImageView *)imageView {
|
||||
if (!_imageView) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (UILabel *)textLabel {
|
||||
if (!_textLabel) {
|
||||
_textLabel = [[UILabel alloc] init];
|
||||
_textLabel.font = [UIFont systemFontOfSize:14];
|
||||
_textLabel.textColor = [UIColor whiteColor];
|
||||
_textLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_textLabel.adjustsFontSizeToFitWidth = YES;
|
||||
_textLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
}
|
||||
return _textLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// FUBeautySkinView.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/21.
|
||||
//
|
||||
// 美肤&美型视图
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "FUBeautySkinViewModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBeautySkinView : UIView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame viewModel:(FUBeautySkinViewModel *)viewModel;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeautySkinCell : UICollectionViewCell
|
||||
|
||||
@property (nonatomic, strong, readonly) UIImageView *imageView;
|
||||
|
||||
@property (nonatomic, strong, readonly) UILabel *textLabel;
|
||||
|
||||
@property (nonatomic, assign) BOOL defaultInMiddle;
|
||||
|
||||
@property (nonatomic, assign) double currentValue;
|
||||
|
||||
@property (nonatomic, assign) double defaultValue;
|
||||
|
||||
@property (nonatomic, copy) NSString *imageName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,269 @@
|
||||
//
|
||||
// FUBeautySkinView.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/21.
|
||||
//
|
||||
|
||||
#import "FUBeautySkinView.h"
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
#import <FUCommonUIComponent/FUCommonUIComponent.h>
|
||||
|
||||
static NSString * const kFUBeautySkinCellIdentifier = @"FUBeautySkinCell";
|
||||
|
||||
@interface FUBeautySkinView ()<UICollectionViewDataSource, UICollectionViewDelegate>
|
||||
|
||||
@property (nonatomic, strong) UICollectionView *skinCollectionView;
|
||||
/// 程度调节
|
||||
@property (nonatomic, strong) FUSlider *slider;
|
||||
/// 恢复按钮
|
||||
@property (nonatomic, strong) FUSquareButton *recoverButton;
|
||||
|
||||
@property (nonatomic, strong) FUBeautySkinViewModel *viewModel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautySkinView
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
return [self initWithFrame:frame viewModel:[[FUBeautySkinViewModel alloc] init]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame viewModel:(FUBeautySkinViewModel *)viewModel {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.viewModel = viewModel;
|
||||
[self configureUI];
|
||||
[self refreshSubviews];
|
||||
[self collectionView:self.skinCollectionView didSelectItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - UI
|
||||
|
||||
- (void)configureUI {
|
||||
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
|
||||
UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
|
||||
effectView.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
|
||||
[self addSubview:effectView];
|
||||
|
||||
[self addSubview:self.slider];
|
||||
[self addSubview:self.recoverButton];
|
||||
NSLayoutConstraint *recoverLeadingConstraint = [NSLayoutConstraint constraintWithItem:self.recoverButton attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1 constant:17];
|
||||
NSLayoutConstraint *recoverBottomConstraint = [NSLayoutConstraint constraintWithItem:self.recoverButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:-6];
|
||||
NSLayoutConstraint *recoverWidthConstraint = [NSLayoutConstraint constraintWithItem:self.recoverButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:44];
|
||||
NSLayoutConstraint *recoverHeightConstraint = [NSLayoutConstraint constraintWithItem:self.recoverButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:74];
|
||||
|
||||
[self addConstraints:@[recoverLeadingConstraint, recoverBottomConstraint]];
|
||||
[self.recoverButton addConstraints:@[recoverWidthConstraint, recoverHeightConstraint]];
|
||||
|
||||
// 分割线
|
||||
UIView *verticalLine = [[UIView alloc] init];
|
||||
verticalLine.backgroundColor = [UIColor colorWithRed:229/255.f green:229/255.f blue:229/255.f alpha:0.2];
|
||||
verticalLine.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self addSubview:verticalLine];
|
||||
NSLayoutConstraint *lineLeadingConstraint = [NSLayoutConstraint constraintWithItem:verticalLine attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.recoverButton attribute:NSLayoutAttributeTrailing multiplier:1 constant:14];
|
||||
NSLayoutConstraint *lineCenterYConstraint = [NSLayoutConstraint constraintWithItem:verticalLine attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.recoverButton attribute:NSLayoutAttributeCenterY multiplier:1 constant:-15];
|
||||
NSLayoutConstraint *lineWidthConstraint = [NSLayoutConstraint constraintWithItem:verticalLine attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:1];
|
||||
NSLayoutConstraint *lineHeightConstraint = [NSLayoutConstraint constraintWithItem:verticalLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:24];
|
||||
[self addConstraints:@[lineLeadingConstraint, lineCenterYConstraint]];
|
||||
[verticalLine addConstraints:@[lineWidthConstraint, lineHeightConstraint]];
|
||||
|
||||
[self addSubview:self.skinCollectionView];
|
||||
NSLayoutConstraint *collectionLeadingConstraint = [NSLayoutConstraint constraintWithItem:self.skinCollectionView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1 constant:76];
|
||||
NSLayoutConstraint *collectionTrailingConstraint = [NSLayoutConstraint constraintWithItem:self.skinCollectionView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
|
||||
NSLayoutConstraint *collectionBottomConstraint = [NSLayoutConstraint constraintWithItem:self.skinCollectionView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
|
||||
NSLayoutConstraint *collectionHeightConstraint = [NSLayoutConstraint constraintWithItem:self.skinCollectionView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:98];
|
||||
[self addConstraints:@[collectionLeadingConstraint, collectionTrailingConstraint, collectionBottomConstraint]];
|
||||
[self.skinCollectionView addConstraint:collectionHeightConstraint];
|
||||
}
|
||||
|
||||
- (void)refreshSubviews {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (self.viewModel.isDefaultValue) {
|
||||
self.recoverButton.alpha = 0.6;
|
||||
self.recoverButton.userInteractionEnabled = NO;
|
||||
} else {
|
||||
self.recoverButton.alpha = 1;
|
||||
self.recoverButton.userInteractionEnabled = YES;
|
||||
}
|
||||
if (!self.slider.hidden && self.viewModel.selectedIndex >= 0) {
|
||||
self.slider.bidirection = self.viewModel.beautySkins[self.viewModel.selectedIndex].defaultValueInMiddle;
|
||||
self.slider.value = self.viewModel.beautySkins[self.viewModel.selectedIndex].currentValue / self.viewModel.beautySkins[self.viewModel.selectedIndex].ratio;
|
||||
}
|
||||
[self.skinCollectionView reloadData];
|
||||
if (self.viewModel.selectedIndex >= 0) {
|
||||
[self.skinCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:self.viewModel.selectedIndex inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Event response
|
||||
|
||||
- (void)recoverAction {
|
||||
[FUAlertManager showAlertWithTitle:nil message:FUBeautyStringWithKey(@"是否将所有参数恢复到默认值") cancel:FUBeautyStringWithKey(@"取消") confirm:FUBeautyStringWithKey(@"确定") inController:nil confirmHandler:^{
|
||||
[self.viewModel recoverAllSkinValuesToDefault];
|
||||
[self refreshSubviews];
|
||||
} cancelHandler:nil];
|
||||
}
|
||||
|
||||
- (void)sliderValueChanged {
|
||||
[self.viewModel setSkinValue:self.slider.value];
|
||||
}
|
||||
|
||||
- (void)sliderChangeEnded {
|
||||
[self refreshSubviews];
|
||||
}
|
||||
|
||||
#pragma mark - Collection view data source
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.viewModel.beautySkins.count;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FUBeautySkinCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kFUBeautySkinCellIdentifier forIndexPath:indexPath];
|
||||
FUBeautySkinModel *skin = self.viewModel.beautySkins[indexPath.item];
|
||||
cell.textLabel.text = FUBeautyStringWithKey(skin.name);
|
||||
cell.imageName = skin.name;
|
||||
cell.defaultInMiddle = skin.defaultValueInMiddle;
|
||||
cell.defaultValue = skin.defaultValue;
|
||||
cell.currentValue = skin.currentValue;
|
||||
cell.selected = indexPath.item == self.viewModel.selectedIndex;
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Collection view delegate
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (indexPath.item == self.viewModel.selectedIndex) {
|
||||
return;
|
||||
}
|
||||
self.viewModel.selectedIndex = indexPath.item;
|
||||
FUBeautySkinModel *skin = self.viewModel.beautySkins[indexPath.item];
|
||||
if (self.slider.hidden) {
|
||||
self.slider.hidden = NO;
|
||||
}
|
||||
self.slider.bidirection = skin.defaultValueInMiddle;
|
||||
self.slider.value = skin.currentValue / skin.ratio;
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UICollectionView *)skinCollectionView {
|
||||
if (!_skinCollectionView) {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
layout.itemSize = CGSizeMake(44, 74);
|
||||
layout.minimumLineSpacing = 22;
|
||||
layout.minimumInteritemSpacing = 22;
|
||||
layout.sectionInset = UIEdgeInsetsMake(16, 16, 6, 16);
|
||||
_skinCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_skinCollectionView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_skinCollectionView.backgroundColor = [UIColor clearColor];
|
||||
_skinCollectionView.showsVerticalScrollIndicator = NO;
|
||||
_skinCollectionView.showsHorizontalScrollIndicator = NO;
|
||||
_skinCollectionView.dataSource = self;
|
||||
_skinCollectionView.delegate = self;
|
||||
[_skinCollectionView registerClass:[FUBeautySkinCell class] forCellWithReuseIdentifier:kFUBeautySkinCellIdentifier];
|
||||
}
|
||||
return _skinCollectionView;
|
||||
}
|
||||
|
||||
- (FUSquareButton *)recoverButton {
|
||||
if (!_recoverButton) {
|
||||
_recoverButton = [[FUSquareButton alloc] initWithFrame:CGRectMake(0, 0, 44, 74)];
|
||||
[_recoverButton setTitle:FUBeautyStringWithKey(@"恢复") forState:UIControlStateNormal];
|
||||
[_recoverButton setImage:[UIImage imageNamed:@"recover_item"] forState:UIControlStateNormal];
|
||||
_recoverButton.alpha = 0.6;
|
||||
_recoverButton.userInteractionEnabled = NO;
|
||||
[_recoverButton addTarget:self action:@selector(recoverAction) forControlEvents:UIControlEventTouchUpInside];
|
||||
_recoverButton.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
}
|
||||
return _recoverButton;
|
||||
}
|
||||
|
||||
-(FUSlider *)slider {
|
||||
if (!_slider) {
|
||||
_slider = [[FUSlider alloc] initWithFrame:CGRectMake(56, 16, CGRectGetWidth(self.frame) - 116, FUBeautyFunctionSliderHeight)];
|
||||
_slider.hidden = YES;//67C367
|
||||
[_slider addTarget:self action:@selector(sliderValueChanged) forControlEvents:UIControlEventValueChanged];
|
||||
[_slider addTarget:self action:@selector(sliderChangeEnded) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
|
||||
}
|
||||
return _slider;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface FUBeautySkinCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *imageView;
|
||||
|
||||
@property (nonatomic, strong) UILabel *textLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautySkinCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self.contentView addSubview:self.imageView];
|
||||
NSLayoutConstraint *imageTop = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1 constant:0];
|
||||
NSLayoutConstraint *imageLeading = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
|
||||
NSLayoutConstraint *imageTrailing = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
|
||||
NSLayoutConstraint *imageHeight = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
|
||||
[self.contentView addConstraints:@[imageTop, imageLeading, imageTrailing]];
|
||||
[self.imageView addConstraint:imageHeight];
|
||||
|
||||
[self.contentView addSubview:self.textLabel];
|
||||
NSLayoutConstraint *textTop = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeBottom multiplier:1 constant:7];
|
||||
NSLayoutConstraint *textLeading = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
|
||||
NSLayoutConstraint *textTrailing = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
|
||||
[self.contentView addConstraints:@[textTop, textLeading, textTrailing]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected {
|
||||
[super setSelected:selected];
|
||||
BOOL changed = NO;
|
||||
if (self.defaultInMiddle) {
|
||||
changed = fabs(self.currentValue - 0.5) > 0.01;
|
||||
}else{
|
||||
changed = self.currentValue > 0.01;
|
||||
}
|
||||
if (selected) {
|
||||
self.imageView.image = changed ? [UIImage imageNamed:[NSString stringWithFormat:@"%@-3", self.imageName]] : [UIImage imageNamed:[NSString stringWithFormat:@"%@-2", self.imageName]];
|
||||
self.textLabel.textColor = [UIColor colorWithRed:103/255.f green:195/255.f blue:103/255.f alpha:1];
|
||||
} else {
|
||||
self.imageView.image = changed ? [UIImage imageNamed:[NSString stringWithFormat:@"%@-1", self.imageName]] : [UIImage imageNamed:[NSString stringWithFormat:@"%@-0", self.imageName]];
|
||||
self.textLabel.textColor = [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImageView *)imageView {
|
||||
if (!_imageView) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (UILabel *)textLabel {
|
||||
if (!_textLabel) {
|
||||
_textLabel = [[UILabel alloc] init];
|
||||
_textLabel.font = [UIFont systemFontOfSize:14];
|
||||
_textLabel.textColor = [UIColor whiteColor];
|
||||
_textLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_textLabel.adjustsFontSizeToFitWidth = YES;
|
||||
_textLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
}
|
||||
return _textLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// FUBeautyFilterViewModel.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/7.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUBeautyFilterModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBeautyFilterViewModel : NSObject
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray<FUBeautyFilterModel *> *beautyFilters;
|
||||
/// 选中滤镜索引
|
||||
@property (nonatomic, assign) NSInteger selectedIndex;
|
||||
|
||||
/// 保存滤镜数据到本地
|
||||
- (void)saveFitersPersistently;
|
||||
|
||||
/// 设置当前滤镜
|
||||
- (void)setCurrentFilter;
|
||||
|
||||
/// 设置滤镜程度
|
||||
/// @param value 程度值
|
||||
- (void)setFilterValue:(double)value;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// FUBeautyFilterViewModel.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/7.
|
||||
//
|
||||
|
||||
#import "FUBeautyFilterViewModel.h"
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
#import <FURenderKit/FURenderKit.h>
|
||||
|
||||
@interface FUBeautyFilterViewModel ()
|
||||
|
||||
@property (nonatomic, copy) NSArray<FUBeautyFilterModel *> *beautyFilters;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautyFilterViewModel
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
if ([[NSUserDefaults standardUserDefaults] objectForKey:FUPersistentBeautyFilterKey]) {
|
||||
// 获取本地滤镜数据
|
||||
self.beautyFilters = [self localFilters];
|
||||
} else {
|
||||
// 获取默认滤镜数据
|
||||
self.beautyFilters = [self defaultFilters];
|
||||
}
|
||||
if ([[NSUserDefaults standardUserDefaults] objectForKey:FUPersistentBeautySelectedFilterIndexKey]) {
|
||||
// 获取本地保存选中的索引
|
||||
_selectedIndex = [[NSUserDefaults standardUserDefaults] integerForKey:FUPersistentBeautySelectedFilterIndexKey];
|
||||
} else {
|
||||
// 默认索引为2
|
||||
_selectedIndex = 2;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Instance methods
|
||||
|
||||
- (void)saveFitersPersistently {
|
||||
if (self.beautyFilters.count == 0) {
|
||||
return;
|
||||
}
|
||||
NSMutableArray *filters = [[NSMutableArray alloc] init];
|
||||
for (FUBeautyFilterModel *model in self. beautyFilters) {
|
||||
NSDictionary *dictionary = [model dictionaryWithValuesForKeys:@[@"filterIndex", @"filterName", @"filterLevel"]];
|
||||
[filters addObject:dictionary];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:filters forKey:FUPersistentBeautyFilterKey];
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:self.selectedIndex forKey:FUPersistentBeautySelectedFilterIndexKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (void)setSelectedIndex:(NSInteger)selectedIndex {
|
||||
if (selectedIndex < 0 || selectedIndex >= self.beautyFilters.count) {
|
||||
return;
|
||||
}
|
||||
[self setFilter:self.beautyFilters[selectedIndex].filterName level:self.beautyFilters[selectedIndex].filterLevel];
|
||||
_selectedIndex = selectedIndex;
|
||||
}
|
||||
|
||||
- (void)setCurrentFilter {
|
||||
if (self.selectedIndex < 0 || self.selectedIndex >= self.beautyFilters.count) {
|
||||
return;
|
||||
}
|
||||
[self setFilter:self.beautyFilters[self.selectedIndex].filterName level:self.beautyFilters[self.selectedIndex].filterLevel];
|
||||
}
|
||||
|
||||
- (void)setFilterValue:(double)value {
|
||||
if (self.selectedIndex < 0 || self.selectedIndex >= self.beautyFilters.count) {
|
||||
return;
|
||||
}
|
||||
FUBeautyFilterModel *model = self.beautyFilters[self.selectedIndex];
|
||||
model.filterLevel = value;
|
||||
[FURenderKit shareRenderKit].beauty.filterLevel = model.filterLevel;
|
||||
}
|
||||
|
||||
#pragma mark - Private methods
|
||||
|
||||
- (void)setFilter:(NSString *)filterName level:(double)filterLevel {
|
||||
[FURenderKit shareRenderKit].beauty.filterName = filterName;
|
||||
[FURenderKit shareRenderKit].beauty.filterLevel = filterLevel;
|
||||
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
[self performSelector:@selector(saveFitersPersistently) withObject:nil afterDelay:2];
|
||||
}
|
||||
|
||||
- (NSArray<FUBeautyFilterModel *> *)localFilters {
|
||||
NSArray *filters = [[NSUserDefaults standardUserDefaults] objectForKey:FUPersistentBeautyFilterKey];
|
||||
NSMutableArray *mutableFilters = [[NSMutableArray alloc] init];
|
||||
for (NSDictionary *filter in filters) {
|
||||
FUBeautyFilterModel *model = [[FUBeautyFilterModel alloc] init];
|
||||
[model setValuesForKeysWithDictionary:filter];
|
||||
[mutableFilters addObject:model];
|
||||
}
|
||||
return [mutableFilters copy];
|
||||
}
|
||||
|
||||
- (NSArray<FUBeautyFilterModel *> *)defaultFilters {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *filterPath = [bundle pathForResource:@"beauty_filter" ofType:@"json"];
|
||||
NSArray<NSDictionary *> *filterData = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filterPath] options:NSJSONReadingMutableContainers error:nil];
|
||||
NSMutableArray *filters = [[NSMutableArray alloc] init];
|
||||
for (NSDictionary *dictionary in filterData) {
|
||||
FUBeautyFilterModel *model = [[FUBeautyFilterModel alloc] init];
|
||||
[model setValuesForKeysWithDictionary:dictionary];
|
||||
[filters addObject:model];
|
||||
}
|
||||
return [filters copy];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// FUBeautyShapeViewModel.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/27.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <FURenderKit/FURenderKit.h>
|
||||
#import "FUBeautyShapeModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBeautyShapeViewModel : NSObject
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray<FUBeautyShapeModel *> *beautyShapes;
|
||||
/// 是否所有值都是默认
|
||||
@property (nonatomic, assign, readonly) BOOL isDefaultValue;
|
||||
/// 当前选中索引,默认为-1
|
||||
@property (nonatomic, assign) NSInteger selectedIndex;
|
||||
/// 美型属性需要根据高低端机适配
|
||||
@property (nonatomic, assign) FUDevicePerformanceLevel performanceLevel;
|
||||
|
||||
/// 保存美型数据到本地
|
||||
- (void)saveShapesPersistently;
|
||||
|
||||
/// 设置单项美型值
|
||||
/// @param value 当前选中单项的值
|
||||
- (void)setShapeValue:(double)value;
|
||||
|
||||
/// 设置当前所有美型值
|
||||
- (void)setAllShapeValues;
|
||||
|
||||
/// 恢复所有美型值为默认
|
||||
- (void)recoverAllShapeValuesToDefault;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,197 @@
|
||||
//
|
||||
// FUBeautyShapeViewModel.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/27.
|
||||
//
|
||||
|
||||
#import "FUBeautyShapeViewModel.h"
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
#import <FURenderKit/FURenderKit.h>
|
||||
|
||||
@interface FUBeautyShapeViewModel ()
|
||||
|
||||
@property (nonatomic, copy) NSArray<FUBeautyShapeModel *> *beautyShapes;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautyShapeViewModel
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
if ([[NSUserDefaults standardUserDefaults] objectForKey:FUPersistentBeautyShapeKey]) {
|
||||
// 获取本地美肤数据
|
||||
self.beautyShapes = [self localShapes];
|
||||
} else {
|
||||
// 获取默认美肤数据
|
||||
self.beautyShapes = [self defaultShapes];
|
||||
}
|
||||
self.selectedIndex = -1;
|
||||
self.performanceLevel = [FURenderKit devicePerformanceLevel];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Instance methods
|
||||
|
||||
- (void)saveShapesPersistently {
|
||||
if (self.beautyShapes.count == 0) {
|
||||
return;
|
||||
}
|
||||
NSMutableArray *shapes = [[NSMutableArray alloc] init];
|
||||
for (FUBeautyShapeModel *model in self.beautyShapes) {
|
||||
NSDictionary *dictionary = [model dictionaryWithValuesForKeys:@[@"name", @"type", @"currentValue", @"defaultValue", @"defaultValueInMiddle", @"differentiateDevicePerformance"]];
|
||||
[shapes addObject:dictionary];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:shapes forKey:FUPersistentBeautyShapeKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (void)setShapeValue:(double)value {
|
||||
if (self.selectedIndex < 0 || self.selectedIndex >= self.beautyShapes.count) {
|
||||
return;
|
||||
}
|
||||
FUBeautyShapeModel *model = self.beautyShapes[self.selectedIndex];
|
||||
model.currentValue = value;
|
||||
[self setValue:model.currentValue forType:model.type];
|
||||
}
|
||||
|
||||
- (void)setAllShapeValues {
|
||||
for (FUBeautyShapeModel *shape in self.beautyShapes) {
|
||||
[self setValue:shape.currentValue forType:shape.type];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)recoverAllShapeValuesToDefault {
|
||||
for (FUBeautyShapeModel *shape in self.beautyShapes) {
|
||||
shape.currentValue = shape.defaultValue;
|
||||
[self setValue:shape.currentValue forType:shape.type];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private methods
|
||||
|
||||
- (void)setValue:(double)value forType:(FUBeautyShape)type {
|
||||
switch (type) {
|
||||
case FUBeautyShapeCheekThinning:
|
||||
[FURenderKit shareRenderKit].beauty.cheekThinning = value;
|
||||
break;
|
||||
case FUBeautyShapeCheekV:
|
||||
[FURenderKit shareRenderKit].beauty.cheekV = value;
|
||||
break;
|
||||
case FUBeautyShapeCheekNarrow:
|
||||
[FURenderKit shareRenderKit].beauty.cheekNarrow = value;
|
||||
break;
|
||||
case FUBeautyShapeCheekShort:
|
||||
[FURenderKit shareRenderKit].beauty.cheekShort = value;
|
||||
break;
|
||||
case FUBeautyShapeCheekSmall:
|
||||
[FURenderKit shareRenderKit].beauty.cheekSmall = value;
|
||||
break;
|
||||
case FUBeautyShapeCheekbones:
|
||||
[FURenderKit shareRenderKit].beauty.intensityCheekbones = value;
|
||||
break;
|
||||
case FUBeautyShapeLowerJaw:
|
||||
[FURenderKit shareRenderKit].beauty.intensityLowerJaw = value;
|
||||
break;
|
||||
case FUBeautyShapeEyeEnlarging:
|
||||
[FURenderKit shareRenderKit].beauty.eyeEnlarging = value;
|
||||
break;
|
||||
case FUBeautyShapeEyeCircle:
|
||||
[FURenderKit shareRenderKit].beauty.intensityEyeCircle = value;
|
||||
break;
|
||||
case FUBeautyShapeChin:
|
||||
[FURenderKit shareRenderKit].beauty.intensityChin = value;
|
||||
break;
|
||||
case FUBeautyShapeForehead:
|
||||
[FURenderKit shareRenderKit].beauty.intensityForehead = value;
|
||||
break;
|
||||
case FUBeautyShapeNose:
|
||||
[FURenderKit shareRenderKit].beauty.intensityNose = value;
|
||||
break;
|
||||
case FUBeautyShapeMouth:
|
||||
[FURenderKit shareRenderKit].beauty.intensityMouth = value;
|
||||
break;
|
||||
case FUBeautyShapeLipThick:
|
||||
[FURenderKit shareRenderKit].beauty.intensityLipThick = value;
|
||||
break;
|
||||
case FUBeautyShapeEyeHeight:
|
||||
[FURenderKit shareRenderKit].beauty.intensityEyeHeight = value;
|
||||
break;
|
||||
case FUBeautyShapeCanthus:
|
||||
[FURenderKit shareRenderKit].beauty.intensityCanthus = value;
|
||||
break;
|
||||
case FUBeautyShapeEyeLid:
|
||||
[FURenderKit shareRenderKit].beauty.intensityEyeLid = value;
|
||||
break;
|
||||
case FUBeautyShapeEyeSpace:
|
||||
[FURenderKit shareRenderKit].beauty.intensityEyeSpace = value;
|
||||
break;
|
||||
case FUBeautyShapeEyeRotate:
|
||||
[FURenderKit shareRenderKit].beauty.intensityEyeRotate = value;
|
||||
break;
|
||||
case FUBeautyShapeLongNose:
|
||||
[FURenderKit shareRenderKit].beauty.intensityLongNose = value;
|
||||
break;
|
||||
case FUBeautyShapePhiltrum:
|
||||
[FURenderKit shareRenderKit].beauty.intensityPhiltrum = value;
|
||||
break;
|
||||
case FUBeautyShapeSmile:
|
||||
[FURenderKit shareRenderKit].beauty.intensitySmile = value;
|
||||
break;
|
||||
case FUBeautyShapeBrowHeight:
|
||||
[FURenderKit shareRenderKit].beauty.intensityBrowHeight = value;
|
||||
break;
|
||||
case FUBeautyShapeBrowSpace:
|
||||
[FURenderKit shareRenderKit].beauty.intensityBrowSpace = value;
|
||||
break;
|
||||
case FUBeautyShapeBrowThick:
|
||||
[FURenderKit shareRenderKit].beauty.intensityBrowThick = value;
|
||||
break;
|
||||
}
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
[self performSelector:@selector(saveShapesPersistently) withObject:nil afterDelay:2];
|
||||
}
|
||||
|
||||
- (NSArray<FUBeautyShapeModel *> *)localShapes {
|
||||
NSArray *shapes = [[NSUserDefaults standardUserDefaults] objectForKey:FUPersistentBeautyShapeKey];
|
||||
NSMutableArray *mutableShapes = [[NSMutableArray alloc] init];
|
||||
for (NSDictionary *shape in shapes) {
|
||||
FUBeautyShapeModel *model = [[FUBeautyShapeModel alloc] init];
|
||||
[model setValuesForKeysWithDictionary:shape];
|
||||
[mutableShapes addObject:model];
|
||||
}
|
||||
return [mutableShapes copy];
|
||||
}
|
||||
|
||||
- (NSArray<FUBeautyShapeModel *> *)defaultShapes {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *shapePath = [bundle pathForResource:@"beauty_shape" ofType:@"json"];
|
||||
NSArray<NSDictionary *> *shapeData = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:shapePath] options:NSJSONReadingMutableContainers error:nil];
|
||||
NSMutableArray *shapes = [[NSMutableArray alloc] init];
|
||||
for (NSDictionary *dictionary in shapeData) {
|
||||
FUBeautyShapeModel *model = [[FUBeautyShapeModel alloc] init];
|
||||
[model setValuesForKeysWithDictionary:dictionary];
|
||||
[shapes addObject:model];
|
||||
}
|
||||
return [shapes copy];
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (BOOL)isDefaultValue {
|
||||
for (FUBeautyShapeModel *shape in self.beautyShapes) {
|
||||
int currentIntValue = shape.defaultValueInMiddle ? (int)(shape.currentValue * 100 - 50) : (int)(shape.currentValue * 100);
|
||||
int defaultIntValue = shape.defaultValueInMiddle ? (int)(shape.defaultValue * 100 - 50) : (int)(shape.defaultValue * 100);
|
||||
if (currentIntValue != defaultIntValue) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// FUBeautySkinViewModel.h
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/27.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUBeautySkinModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUBeautySkinViewModel : NSObject
|
||||
|
||||
@property (nonatomic, copy, readonly) NSArray<FUBeautySkinModel *> *beautySkins;
|
||||
/// 是否所有值都是默认
|
||||
@property (nonatomic, assign, readonly) BOOL isDefaultValue;
|
||||
/// 当前选中索引,默认为-1
|
||||
@property (nonatomic, assign) NSInteger selectedIndex;
|
||||
|
||||
/// 保存美肤数据到本地
|
||||
- (void)saveSkinsPersistently;
|
||||
|
||||
/// 设置单项美肤值
|
||||
/// @param value 当前选中单项的值
|
||||
- (void)setSkinValue:(double)value;
|
||||
|
||||
/// 设置当前所有美肤值
|
||||
- (void)setAllSkinValues;
|
||||
|
||||
/// 恢复所有美肤值为默认
|
||||
- (void)recoverAllSkinValuesToDefault;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,148 @@
|
||||
//
|
||||
// FUBeautySkinViewModel.m
|
||||
// FUBeautyComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/7/27.
|
||||
//
|
||||
|
||||
#import "FUBeautySkinViewModel.h"
|
||||
#import "FUBeautyDefine.h"
|
||||
|
||||
#import <FURenderKit/FURenderKit.h>
|
||||
|
||||
@interface FUBeautySkinViewModel ()
|
||||
|
||||
@property (nonatomic, copy) NSArray<FUBeautySkinModel *> *beautySkins;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUBeautySkinViewModel
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
if ([[NSUserDefaults standardUserDefaults] objectForKey:FUPersistentBeautySkinKey]) {
|
||||
// 获取本地美肤数据
|
||||
self.beautySkins = [self localSkins];
|
||||
} else {
|
||||
// 获取默认美肤数据
|
||||
self.beautySkins = [self defaultSkins];
|
||||
}
|
||||
self.selectedIndex = -1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Instance methods
|
||||
|
||||
- (void)saveSkinsPersistently {
|
||||
if (self.beautySkins.count == 0) {
|
||||
return;
|
||||
}
|
||||
NSMutableArray *skins = [[NSMutableArray alloc] init];
|
||||
for (FUBeautySkinModel *model in self.beautySkins) {
|
||||
NSDictionary *dictionary = [model dictionaryWithValuesForKeys:@[@"name", @"type", @"currentValue", @"defaultValue", @"defaultValueInMiddle", @"ratio"]];
|
||||
[skins addObject:dictionary];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:skins forKey:FUPersistentBeautySkinKey];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (void)setSkinValue:(double)value {
|
||||
if (self.selectedIndex < 0 || self.selectedIndex >= self.beautySkins.count) {
|
||||
return;
|
||||
}
|
||||
FUBeautySkinModel *model = self.beautySkins[self.selectedIndex];
|
||||
model.currentValue = value * model.ratio;
|
||||
[self setValue:model.currentValue forType:model.type];
|
||||
}
|
||||
|
||||
- (void)setAllSkinValues {
|
||||
for (FUBeautySkinModel *skin in self.beautySkins) {
|
||||
[self setValue:skin.currentValue forType:skin.type];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)recoverAllSkinValuesToDefault {
|
||||
for (FUBeautySkinModel *skin in self.beautySkins) {
|
||||
skin.currentValue = skin.defaultValue;
|
||||
[self setValue:skin.currentValue forType:skin.type];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private methods
|
||||
|
||||
- (void)setValue:(double)value forType:(FUBeautySkin)type {
|
||||
switch (type) {
|
||||
case FUBeautySkinBlurLevel:
|
||||
[FURenderKit shareRenderKit].beauty.blurLevel = value;
|
||||
break;
|
||||
case FUBeautySkinColorLevel:
|
||||
[FURenderKit shareRenderKit].beauty.colorLevel = value;
|
||||
break;
|
||||
case FUBeautySkinRedLevel:
|
||||
[FURenderKit shareRenderKit].beauty.redLevel = value;
|
||||
break;
|
||||
case FUBeautySkinSharpen:
|
||||
[FURenderKit shareRenderKit].beauty.sharpen = value;
|
||||
break;
|
||||
case FUBeautySkinFaceThreed:
|
||||
[FURenderKit shareRenderKit].beauty.faceThreed = value;
|
||||
break;
|
||||
case FUBeautySkinEyeBright:
|
||||
[FURenderKit shareRenderKit].beauty.eyeBright = value;
|
||||
break;
|
||||
case FUBeautySkinToothWhiten:
|
||||
[FURenderKit shareRenderKit].beauty.toothWhiten = value;
|
||||
break;
|
||||
case FUBeautySkinRemovePouchStrength:
|
||||
[FURenderKit shareRenderKit].beauty.removePouchStrength = value;
|
||||
break;
|
||||
case FUBeautySkinRemoveNasolabialFoldsStrength:
|
||||
[FURenderKit shareRenderKit].beauty.removeNasolabialFoldsStrength = value;
|
||||
break;
|
||||
}
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
[self performSelector:@selector(saveSkinsPersistently) withObject:nil afterDelay:2];
|
||||
}
|
||||
|
||||
- (NSArray<FUBeautySkinModel *> *)localSkins {
|
||||
NSArray *skins = [[NSUserDefaults standardUserDefaults] objectForKey:FUPersistentBeautySkinKey];
|
||||
NSMutableArray *mutableSkins = [[NSMutableArray alloc] init];
|
||||
for (NSDictionary *skin in skins) {
|
||||
FUBeautySkinModel *model = [[FUBeautySkinModel alloc] init];
|
||||
[model setValuesForKeysWithDictionary:skin];
|
||||
[mutableSkins addObject:model];
|
||||
}
|
||||
return [mutableSkins copy];
|
||||
}
|
||||
|
||||
- (NSArray<FUBeautySkinModel *> *)defaultSkins {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *skinPath = [bundle pathForResource:@"beauty_skin" ofType:@"json"];
|
||||
NSArray<NSDictionary *> *skinData = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:skinPath] options:NSJSONReadingMutableContainers error:nil];
|
||||
NSMutableArray *skins = [[NSMutableArray alloc] init];
|
||||
for (NSDictionary *dictionary in skinData) {
|
||||
FUBeautySkinModel *model = [[FUBeautySkinModel alloc] init];
|
||||
[model setValuesForKeysWithDictionary:dictionary];
|
||||
[skins addObject:model];
|
||||
}
|
||||
return [skins copy];
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (BOOL)isDefaultValue {
|
||||
for (FUBeautySkinModel *skin in self.beautySkins) {
|
||||
int currentIntValue = skin.defaultValueInMiddle ? (int)(skin.currentValue / skin.ratio * 100 - 50) : (int)(skin.currentValue / skin.ratio * 100);
|
||||
int defaultIntValue = skin.defaultValueInMiddle ? (int)(skin.defaultValue / skin.ratio * 100 - 50) : (int)(skin.defaultValue / skin.ratio * 100);
|
||||
if (currentIntValue != defaultIntValue) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
BIN
Example/SubModules/FUCommonUIComponent/.DS_Store
vendored
Normal file
BIN
Example/SubModules/FUCommonUIComponent/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "FUCommonUIComponent"
|
||||
s.version = "1.0"
|
||||
s.license = 'MIT'
|
||||
s.summary = "UI components"
|
||||
s.description = "Some UI components of FULiveDemo."
|
||||
s.homepage = "https://github.com/Faceunity/FULiveDemo"
|
||||
s.author = { 'faceunity' => 'dev@faceunity.com' }
|
||||
s.platform = :ios, "9.0"
|
||||
s.source = { "http": "https://github.com/Faceunity/FULiveDemo"}
|
||||
s.source_files = '**/*.{h,m}'
|
||||
# s.resources = 'FUCommonUIComponent/Resource/**/*.{png,xcassets}'
|
||||
s.requires_arc = true
|
||||
end
|
||||
|
||||
@@ -0,0 +1,482 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 55;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
E3406A45288AAC5000373612 /* FUSquareButton.m in Sources */ = {isa = PBXBuildFile; fileRef = E3406A43288AAC5000373612 /* FUSquareButton.m */; };
|
||||
E3406A46288AAC5000373612 /* FUSquareButton.h in Headers */ = {isa = PBXBuildFile; fileRef = E3406A44288AAC5000373612 /* FUSquareButton.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E34CFFA02892873900712C63 /* FUAlertController.m in Sources */ = {isa = PBXBuildFile; fileRef = E34CFF9C2892873800712C63 /* FUAlertController.m */; };
|
||||
E34CFFA12892873900712C63 /* FUAlertManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E34CFF9D2892873900712C63 /* FUAlertManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E34CFFA22892873900712C63 /* FUAlertManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E34CFF9E2892873900712C63 /* FUAlertManager.m */; };
|
||||
E34CFFA32892873900712C63 /* FUAlertController.h in Headers */ = {isa = PBXBuildFile; fileRef = E34CFF9F2892873900712C63 /* FUAlertController.h */; };
|
||||
E35333632865AEDF00FFED9D /* FUItemsView.h in Headers */ = {isa = PBXBuildFile; fileRef = E35333612865AEDF00FFED9D /* FUItemsView.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E35333642865AEDF00FFED9D /* FUItemsView.m in Sources */ = {isa = PBXBuildFile; fileRef = E35333622865AEDF00FFED9D /* FUItemsView.m */; };
|
||||
E35333672865AF7600FFED9D /* FUItemCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E35333652865AF7600FFED9D /* FUItemCell.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E35333682865AF7600FFED9D /* FUItemCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E35333662865AF7600FFED9D /* FUItemCell.m */; };
|
||||
E36A0825285C895900A83553 /* FUCommonUIComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = E36A0824285C895900A83553 /* FUCommonUIComponent.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E36A082D285C89C200A83553 /* FUSegmentBar.m in Sources */ = {isa = PBXBuildFile; fileRef = E36A082B285C89C200A83553 /* FUSegmentBar.m */; };
|
||||
E36A082E285C89C200A83553 /* FUSegmentBar.h in Headers */ = {isa = PBXBuildFile; fileRef = E36A082C285C89C200A83553 /* FUSegmentBar.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E3FF96232860591F004B13D7 /* FUSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = E3FF96212860591F004B13D7 /* FUSlider.m */; };
|
||||
E3FF96242860591F004B13D7 /* FUSlider.h in Headers */ = {isa = PBXBuildFile; fileRef = E3FF96222860591F004B13D7 /* FUSlider.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E3FF962728605987004B13D7 /* FUCommonUIComponent.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E3FF962628605987004B13D7 /* FUCommonUIComponent.xcassets */; };
|
||||
E3FF962E28605CA5004B13D7 /* FUInsetsLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = E3FF962C28605CA5004B13D7 /* FUInsetsLabel.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E3FF962F28605CA5004B13D7 /* FUInsetsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = E3FF962D28605CA5004B13D7 /* FUInsetsLabel.m */; };
|
||||
E3FF963328605F66004B13D7 /* FUTipHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = E3FF963128605F66004B13D7 /* FUTipHUD.m */; };
|
||||
E3FF963428605F66004B13D7 /* FUTipHUD.h in Headers */ = {isa = PBXBuildFile; fileRef = E3FF963228605F66004B13D7 /* FUTipHUD.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E3FF966628606435004B13D7 /* FUCommonUIDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = E3FF9628286059F4004B13D7 /* FUCommonUIDefine.h */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
E3406A43288AAC5000373612 /* FUSquareButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSquareButton.m; sourceTree = "<group>"; };
|
||||
E3406A44288AAC5000373612 /* FUSquareButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUSquareButton.h; sourceTree = "<group>"; };
|
||||
E34CFF9C2892873800712C63 /* FUAlertController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUAlertController.m; sourceTree = "<group>"; };
|
||||
E34CFF9D2892873900712C63 /* FUAlertManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUAlertManager.h; sourceTree = "<group>"; };
|
||||
E34CFF9E2892873900712C63 /* FUAlertManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUAlertManager.m; sourceTree = "<group>"; };
|
||||
E34CFF9F2892873900712C63 /* FUAlertController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUAlertController.h; sourceTree = "<group>"; };
|
||||
E35333612865AEDF00FFED9D /* FUItemsView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUItemsView.h; sourceTree = "<group>"; };
|
||||
E35333622865AEDF00FFED9D /* FUItemsView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUItemsView.m; sourceTree = "<group>"; };
|
||||
E35333652865AF7600FFED9D /* FUItemCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUItemCell.h; sourceTree = "<group>"; };
|
||||
E35333662865AF7600FFED9D /* FUItemCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUItemCell.m; sourceTree = "<group>"; };
|
||||
E36A0821285C895900A83553 /* FUCommonUIComponent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FUCommonUIComponent.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E36A0824285C895900A83553 /* FUCommonUIComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUCommonUIComponent.h; sourceTree = "<group>"; };
|
||||
E36A082B285C89C200A83553 /* FUSegmentBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSegmentBar.m; sourceTree = "<group>"; };
|
||||
E36A082C285C89C200A83553 /* FUSegmentBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUSegmentBar.h; sourceTree = "<group>"; };
|
||||
E3FF96212860591F004B13D7 /* FUSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUSlider.m; sourceTree = "<group>"; };
|
||||
E3FF96222860591F004B13D7 /* FUSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUSlider.h; sourceTree = "<group>"; };
|
||||
E3FF962628605987004B13D7 /* FUCommonUIComponent.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = FUCommonUIComponent.xcassets; sourceTree = "<group>"; };
|
||||
E3FF9628286059F4004B13D7 /* FUCommonUIDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUCommonUIDefine.h; sourceTree = "<group>"; };
|
||||
E3FF962C28605CA5004B13D7 /* FUInsetsLabel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUInsetsLabel.h; sourceTree = "<group>"; };
|
||||
E3FF962D28605CA5004B13D7 /* FUInsetsLabel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUInsetsLabel.m; sourceTree = "<group>"; };
|
||||
E3FF963128605F66004B13D7 /* FUTipHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FUTipHUD.m; sourceTree = "<group>"; };
|
||||
E3FF963228605F66004B13D7 /* FUTipHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FUTipHUD.h; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
E36A081E285C895900A83553 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
E3406A42288AAC3F00373612 /* FUSquareButton */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E3406A44288AAC5000373612 /* FUSquareButton.h */,
|
||||
E3406A43288AAC5000373612 /* FUSquareButton.m */,
|
||||
);
|
||||
path = FUSquareButton;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E34CFF9B2892871E00712C63 /* FUAlert */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E34CFF9F2892873900712C63 /* FUAlertController.h */,
|
||||
E34CFF9C2892873800712C63 /* FUAlertController.m */,
|
||||
E34CFF9D2892873900712C63 /* FUAlertManager.h */,
|
||||
E34CFF9E2892873900712C63 /* FUAlertManager.m */,
|
||||
);
|
||||
path = FUAlert;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E35333602865AD1200FFED9D /* FUItemsView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E35333612865AEDF00FFED9D /* FUItemsView.h */,
|
||||
E35333622865AEDF00FFED9D /* FUItemsView.m */,
|
||||
E35333652865AF7600FFED9D /* FUItemCell.h */,
|
||||
E35333662865AF7600FFED9D /* FUItemCell.m */,
|
||||
);
|
||||
path = FUItemsView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E36A0817285C895900A83553 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E36A0823285C895900A83553 /* FUCommonUIComponent */,
|
||||
E36A0822285C895900A83553 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E36A0822285C895900A83553 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E36A0821285C895900A83553 /* FUCommonUIComponent.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E36A0823285C895900A83553 /* FUCommonUIComponent */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E34CFF9B2892871E00712C63 /* FUAlert */,
|
||||
E3406A42288AAC3F00373612 /* FUSquareButton */,
|
||||
E35333602865AD1200FFED9D /* FUItemsView */,
|
||||
E3FF963028605F24004B13D7 /* FUTipHUD */,
|
||||
E3FF962B28605C79004B13D7 /* FUInsetsLabel */,
|
||||
E3FF962A28605B8C004B13D7 /* FUSegmentBar */,
|
||||
E3FF962928605B86004B13D7 /* FUSlider */,
|
||||
E3FF96252860596A004B13D7 /* Resource */,
|
||||
E36A0824285C895900A83553 /* FUCommonUIComponent.h */,
|
||||
E3FF9628286059F4004B13D7 /* FUCommonUIDefine.h */,
|
||||
);
|
||||
path = FUCommonUIComponent;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E3FF96252860596A004B13D7 /* Resource */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E3FF962628605987004B13D7 /* FUCommonUIComponent.xcassets */,
|
||||
);
|
||||
path = Resource;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E3FF962928605B86004B13D7 /* FUSlider */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E3FF96222860591F004B13D7 /* FUSlider.h */,
|
||||
E3FF96212860591F004B13D7 /* FUSlider.m */,
|
||||
);
|
||||
path = FUSlider;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E3FF962A28605B8C004B13D7 /* FUSegmentBar */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E36A082C285C89C200A83553 /* FUSegmentBar.h */,
|
||||
E36A082B285C89C200A83553 /* FUSegmentBar.m */,
|
||||
);
|
||||
path = FUSegmentBar;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E3FF962B28605C79004B13D7 /* FUInsetsLabel */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E3FF962C28605CA5004B13D7 /* FUInsetsLabel.h */,
|
||||
E3FF962D28605CA5004B13D7 /* FUInsetsLabel.m */,
|
||||
);
|
||||
path = FUInsetsLabel;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E3FF963028605F24004B13D7 /* FUTipHUD */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E3FF963228605F66004B13D7 /* FUTipHUD.h */,
|
||||
E3FF963128605F66004B13D7 /* FUTipHUD.m */,
|
||||
);
|
||||
path = FUTipHUD;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
E36A081C285C895900A83553 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E3FF96242860591F004B13D7 /* FUSlider.h in Headers */,
|
||||
E34CFFA32892873900712C63 /* FUAlertController.h in Headers */,
|
||||
E36A0825285C895900A83553 /* FUCommonUIComponent.h in Headers */,
|
||||
E3FF962E28605CA5004B13D7 /* FUInsetsLabel.h in Headers */,
|
||||
E35333632865AEDF00FFED9D /* FUItemsView.h in Headers */,
|
||||
E3406A46288AAC5000373612 /* FUSquareButton.h in Headers */,
|
||||
E35333672865AF7600FFED9D /* FUItemCell.h in Headers */,
|
||||
E3FF966628606435004B13D7 /* FUCommonUIDefine.h in Headers */,
|
||||
E34CFFA12892873900712C63 /* FUAlertManager.h in Headers */,
|
||||
E36A082E285C89C200A83553 /* FUSegmentBar.h in Headers */,
|
||||
E3FF963428605F66004B13D7 /* FUTipHUD.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
E36A0820285C895900A83553 /* FUCommonUIComponent */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = E36A0828285C895900A83553 /* Build configuration list for PBXNativeTarget "FUCommonUIComponent" */;
|
||||
buildPhases = (
|
||||
E36A081C285C895900A83553 /* Headers */,
|
||||
E36A081D285C895900A83553 /* Sources */,
|
||||
E36A081E285C895900A83553 /* Frameworks */,
|
||||
E36A081F285C895900A83553 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = FUCommonUIComponent;
|
||||
productName = FUCommonUIComponent;
|
||||
productReference = E36A0821285C895900A83553 /* FUCommonUIComponent.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
E36A0818285C895900A83553 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastUpgradeCheck = 1330;
|
||||
TargetAttributes = {
|
||||
E36A0820285C895900A83553 = {
|
||||
CreatedOnToolsVersion = 13.3.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = E36A081B285C895900A83553 /* Build configuration list for PBXProject "FUCommonUIComponent" */;
|
||||
compatibilityVersion = "Xcode 13.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = E36A0817285C895900A83553;
|
||||
productRefGroup = E36A0822285C895900A83553 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
E36A0820285C895900A83553 /* FUCommonUIComponent */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
E36A081F285C895900A83553 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E3FF962728605987004B13D7 /* FUCommonUIComponent.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
E36A081D285C895900A83553 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E35333642865AEDF00FFED9D /* FUItemsView.m in Sources */,
|
||||
E36A082D285C89C200A83553 /* FUSegmentBar.m in Sources */,
|
||||
E34CFFA22892873900712C63 /* FUAlertManager.m in Sources */,
|
||||
E3FF96232860591F004B13D7 /* FUSlider.m in Sources */,
|
||||
E35333682865AF7600FFED9D /* FUItemCell.m in Sources */,
|
||||
E34CFFA02892873900712C63 /* FUAlertController.m in Sources */,
|
||||
E3FF963328605F66004B13D7 /* FUTipHUD.m in Sources */,
|
||||
E3FF962F28605CA5004B13D7 /* FUInsetsLabel.m in Sources */,
|
||||
E3406A45288AAC5000373612 /* FUSquareButton.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
E36A0826285C895900A83553 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.4;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
E36A0827285C895900A83553 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
E36A0829285C895900A83553 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 35A6KD62ZJ;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = faceunity.FUCommonUIComponent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
E36A082A285C895900A83553 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 35A6KD62ZJ;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = faceunity.FUCommonUIComponent;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
E36A081B285C895900A83553 /* Build configuration list for PBXProject "FUCommonUIComponent" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
E36A0826285C895900A83553 /* Debug */,
|
||||
E36A0827285C895900A83553 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
E36A0828285C895900A83553 /* Build configuration list for PBXNativeTarget "FUCommonUIComponent" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
E36A0829285C895900A83553 /* Debug */,
|
||||
E36A082A285C895900A83553 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = E36A0818285C895900A83553 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1330"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E36A0820285C895900A83553"
|
||||
BuildableName = "FUCommonUIComponent.framework"
|
||||
BlueprintName = "FUCommonUIComponent"
|
||||
ReferencedContainer = "container:FUCommonUIComponent.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E36A0820285C895900A83553"
|
||||
BuildableName = "FUCommonUIComponent.framework"
|
||||
BlueprintName = "FUCommonUIComponent"
|
||||
ReferencedContainer = "container:FUCommonUIComponent.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
BIN
Example/SubModules/FUCommonUIComponent/FUCommonUIComponent/.DS_Store
vendored
Normal file
BIN
Example/SubModules/FUCommonUIComponent/FUCommonUIComponent/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// FUAlertController.h
|
||||
//
|
||||
// Created by 项林平 on 2019/6/21.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class FUAlertController;
|
||||
|
||||
@interface FUAlertModel : NSObject
|
||||
@property (nonatomic, copy) NSString *alertTitle;
|
||||
@property (nonatomic, copy) NSString *alertMessage;
|
||||
@property (nonatomic, assign) UIAlertControllerStyle preferredStyle;
|
||||
|
||||
- (instancetype) initWithTitle:(NSString *)title message:(NSString *)message style:(UIAlertControllerStyle)style;
|
||||
|
||||
@end
|
||||
|
||||
typedef void (^FUAlert)(FUAlertController *controller);
|
||||
typedef FUAlertController * _Nonnull (^FUShowAlert)(UIViewController *controller);
|
||||
typedef FUAlertController * _Nonnull (^FUActions)(NSArray<UIAlertAction *> *actions);
|
||||
typedef FUAlertController * _Nullable (^FUSourceView)(UIView *sourceView);
|
||||
|
||||
@interface FUAlertController : UIAlertController
|
||||
|
||||
+ (FUAlertController *)makeAlert:(FUAlert)block alertModel:(FUAlertModel *)model;
|
||||
|
||||
/**
|
||||
设置Actions
|
||||
|
||||
@return Self
|
||||
*/
|
||||
- (FUActions)actionItems;
|
||||
|
||||
/**
|
||||
当设备为iPad时设置SourceView
|
||||
|
||||
@return Self
|
||||
*/
|
||||
- (FUSourceView)sourceView;
|
||||
|
||||
/**
|
||||
显示Alert
|
||||
|
||||
@return Self
|
||||
*/
|
||||
- (FUShowAlert)showAlert;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// FUAlertController.m
|
||||
//
|
||||
// Created by 项林平 on 2019/6/21.
|
||||
//
|
||||
|
||||
#import "FUAlertController.h"
|
||||
|
||||
@implementation FUAlertModel
|
||||
|
||||
- (instancetype)initWithTitle:(NSString *)title message:(NSString *)message style:(UIAlertControllerStyle)style {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.alertTitle = title;
|
||||
self.alertMessage = message;
|
||||
self.preferredStyle = style;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FUAlertController
|
||||
+(FUAlertController *)makeAlert:(FUAlert)block alertModel:(FUAlertModel *)model {
|
||||
FUAlertController *alert = [FUAlertController alertControllerWithTitle:model.alertTitle message:model.alertMessage preferredStyle:model.preferredStyle];
|
||||
block(alert);
|
||||
return alert;
|
||||
}
|
||||
- (FUActions)actionItems {
|
||||
FUActions actionsBlock = ^(NSArray<UIAlertAction *> *actions) {
|
||||
[actions enumerateObjectsUsingBlock:^(UIAlertAction * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[self addAction:obj];
|
||||
}];
|
||||
return self;
|
||||
};
|
||||
return actionsBlock;
|
||||
}
|
||||
- (FUShowAlert)showAlert {
|
||||
FUShowAlert showBlock = ^(UIViewController *controller) {
|
||||
[controller presentViewController:self animated:YES completion:nil];
|
||||
return self;
|
||||
};
|
||||
return showBlock;
|
||||
}
|
||||
- (FUSourceView)sourceView {
|
||||
FUSourceView sourceViewBlock = ^(UIView *sourceView) {
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad && sourceView) {
|
||||
self.popoverPresentationController.sourceView = sourceView;
|
||||
self.popoverPresentationController.sourceRect = sourceView.bounds;
|
||||
self.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionAny;
|
||||
}
|
||||
return self;
|
||||
};
|
||||
return sourceViewBlock;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// FUAlertManager.h
|
||||
//
|
||||
// Created by 项林平 on 2019/9/25.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUAlertManager : NSObject
|
||||
|
||||
/// Alert
|
||||
/// @param titleString title
|
||||
/// @param messageString message
|
||||
/// @param cancelString 取消
|
||||
/// @param confirmString 确定
|
||||
/// @param viewController 控制器
|
||||
/// @param confirm 确定闭包
|
||||
/// @param cancel 取消闭包
|
||||
+ (void)showAlertWithTitle:(nullable NSString *)titleString
|
||||
message:(nullable NSString *)messageString
|
||||
cancel:(nullable NSString *)cancelString
|
||||
confirm:(nullable NSString *)confirmString
|
||||
inController:(nullable UIViewController *)viewController
|
||||
confirmHandler:(nullable void (^)(void))confirm
|
||||
cancelHandler:(nullable void (^)(void))cancel;
|
||||
|
||||
/// ActionSheet
|
||||
/// @param titleString title
|
||||
/// @param messageString message
|
||||
/// @param cancelString 取消
|
||||
/// @param viewController 控制器
|
||||
/// @param sourceView 设备为iPad时需要传入
|
||||
/// @param actions 选项
|
||||
/// @param actionHandler 选项闭包
|
||||
+ (void)showActionSheetWithTitle:(nullable NSString *)titleString
|
||||
message:(nullable NSString *)messageString
|
||||
cancel:(nullable NSString *)cancelString
|
||||
inController:(nullable UIViewController *)viewController
|
||||
sourceView:(nullable UIView *)sourceView
|
||||
actions:(NSArray<NSString *> *)actions
|
||||
actionHandler:(nullable void (^)(NSInteger index))actionHandler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// FUAlertManager.m
|
||||
//
|
||||
// Created by 项林平 on 2019/9/25.
|
||||
//
|
||||
|
||||
#import "FUAlertManager.h"
|
||||
#import "FUAlertController.h"
|
||||
|
||||
@implementation FUAlertManager
|
||||
|
||||
+ (void)showAlertWithTitle:(NSString *)titleString
|
||||
message:(NSString *)messageString
|
||||
cancel:(NSString *)cancelString
|
||||
confirm:(NSString *)confirmString
|
||||
inController:(UIViewController *)viewController
|
||||
confirmHandler:(void (^)(void))confirm
|
||||
cancelHandler:(void (^)(void))cancel {
|
||||
if (!cancelString && !confirmString) {
|
||||
return;
|
||||
}
|
||||
FUAlertModel *alertModel = [[FUAlertModel alloc] initWithTitle:titleString message:messageString style:UIAlertControllerStyleAlert];
|
||||
__block UIViewController *currentViewController = viewController;
|
||||
[FUAlertController makeAlert:^(FUAlertController * _Nonnull controller) {
|
||||
NSMutableArray *items = [[NSMutableArray alloc] init];
|
||||
if (cancelString) {
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelString style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||||
if (cancel) {
|
||||
cancel();
|
||||
}
|
||||
}];
|
||||
//设置Action文字颜色
|
||||
[cancelAction setValue:[UIColor colorWithRed:44/255.0 green:46/255.0 blue:48/255.0 alpha:1.0] forKey:@"titleTextColor"];
|
||||
[items addObject:cancelAction];
|
||||
}
|
||||
|
||||
if (confirmString) {
|
||||
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:confirmString style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||
if (confirm) {
|
||||
confirm();
|
||||
}
|
||||
}];
|
||||
[confirmAction setValue:[UIColor colorWithRed:103/255.f green:195/255.f blue:103/255.f alpha:1] forKey:@"titleTextColor"];
|
||||
[items addObject:confirmAction];
|
||||
}
|
||||
if (!currentViewController) {
|
||||
currentViewController = [self topViewController];
|
||||
}
|
||||
if (!currentViewController) {
|
||||
NSLog(@"FUAlert: viewController can not be nil!");
|
||||
return;
|
||||
}
|
||||
controller.actionItems(items).showAlert(currentViewController);
|
||||
} alertModel:alertModel];
|
||||
}
|
||||
+ (void)showActionSheetWithTitle:(NSString *)titleString
|
||||
message:(NSString *)messageString
|
||||
cancel:(NSString *)cancelString
|
||||
inController:(UIViewController *)viewController
|
||||
sourceView:(UIView *)sourceView
|
||||
actions:(NSArray<NSString *> *)actions
|
||||
actionHandler:(void (^)(NSInteger))actionHandler {
|
||||
if (actions.count == 0) {
|
||||
return;
|
||||
}
|
||||
FUAlertModel *alertModel = [[FUAlertModel alloc] initWithTitle:titleString message:messageString style:UIAlertControllerStyleActionSheet];
|
||||
__block UIViewController *currentViewController = viewController;
|
||||
[FUAlertController makeAlert:^(FUAlertController * _Nonnull controller) {
|
||||
NSMutableArray *items = [[NSMutableArray alloc] init];
|
||||
if (cancelString) {
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelString style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
|
||||
}];
|
||||
[items addObject:cancelAction];
|
||||
}
|
||||
[actions enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
UIAlertAction *alertAction = [UIAlertAction actionWithTitle:obj style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||||
if (actionHandler) {
|
||||
actionHandler(idx);
|
||||
}
|
||||
}];
|
||||
[items addObject:alertAction];
|
||||
}];
|
||||
if (!currentViewController) {
|
||||
currentViewController = [self topViewController];
|
||||
}
|
||||
if (!currentViewController) {
|
||||
NSLog(@"FUAlert: viewController can not be nil!");
|
||||
return;
|
||||
}
|
||||
controller.actionItems(items).sourceView(sourceView).showAlert(currentViewController);
|
||||
} alertModel:alertModel];
|
||||
}
|
||||
|
||||
+ (UIViewController *)topViewController {
|
||||
UIViewController *root = [UIApplication sharedApplication].delegate.window.rootViewController;
|
||||
return [self currentViewControllerWithRootViewController:root];
|
||||
}
|
||||
|
||||
+ (UIViewController *)currentViewControllerWithRootViewController:(UIViewController *)viewController {
|
||||
if (viewController.presentedViewController) {
|
||||
return [self currentViewControllerWithRootViewController:viewController.presentedViewController];
|
||||
} else if ([viewController isKindOfClass:[UINavigationController class]]) {
|
||||
UINavigationController *navigation = (UINavigationController *)viewController;
|
||||
return [self currentViewControllerWithRootViewController:navigation.visibleViewController];
|
||||
} else if ([viewController isKindOfClass:[UITabBarController class]]) {
|
||||
UITabBarController *tabBar = (UITabBarController *)viewController;
|
||||
return [self currentViewControllerWithRootViewController:tabBar.selectedViewController];
|
||||
} else {
|
||||
return viewController;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// FUCommonUIComponent.h
|
||||
// FUCommonUIComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/17.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "FUSegmentBar.h"
|
||||
#import "FUTipHUD.h"
|
||||
#import "FUInsetsLabel.h"
|
||||
#import "FUSlider.h"
|
||||
#import "FUItemsView.h"
|
||||
#import "FUItemCell.h"
|
||||
#import "FUSquareButton.h"
|
||||
#import "FUAlertManager.h"
|
||||
|
||||
|
||||
//! Project version number for FUCommonUIComponent.
|
||||
FOUNDATION_EXPORT double FUCommonUIComponentVersionNumber;
|
||||
|
||||
//! Project version string for FUCommonUIComponent.
|
||||
FOUNDATION_EXPORT const unsigned char FUCommonUIComponentVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <FUCommonUIComponent/PublicHeader.h>
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// FUCommonUIDefine.h
|
||||
// FUCommonUIComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/20.
|
||||
//
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#ifndef FUCommonUIDefine_h
|
||||
#define FUCommonUIDefine_h
|
||||
|
||||
static inline UIImage * FUCommonUIImageNamed(NSString *name) {
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:@"FUCommonUIComponent" ofType:@"framework" inDirectory:@"Frameworks"];
|
||||
NSBundle *bundle = [NSBundle bundleWithPath:path];
|
||||
return [UIImage imageNamed:name inBundle:bundle compatibleWithTraitCollection:nil];;
|
||||
}
|
||||
|
||||
#endif /* FUCommonUIDefine_h */
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// FUInsetsLabel.h
|
||||
// FUCommonUIComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/20.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUInsetsLabel : UILabel
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame insets:(UIEdgeInsets)insets;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// FUInsetsLabel.m
|
||||
// FUCommonUIComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/20.
|
||||
//
|
||||
|
||||
#import "FUInsetsLabel.h"
|
||||
|
||||
@interface FUInsetsLabel ()
|
||||
|
||||
@property (nonatomic) UIEdgeInsets insets;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUInsetsLabel
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
return [self initWithFrame:frame insets:UIEdgeInsetsMake(8, 8, 8, 8)];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame insets:(UIEdgeInsets)insets {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.insets = insets;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)drawTextInRect:(CGRect)rect {
|
||||
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.insets)];
|
||||
}
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
CGSize fitSize = [super sizeThatFits:size];
|
||||
fitSize.width += self.insets.left + self.insets.right;
|
||||
fitSize.height += self.insets.top + self.insets.bottom;
|
||||
return fitSize;
|
||||
}
|
||||
|
||||
- (CGSize)intrinsicContentSize {
|
||||
CGSize contentSize = [super intrinsicContentSize];
|
||||
contentSize.width += self.insets.left + self.insets.right;
|
||||
contentSize.height += self.insets.top + self.insets.bottom;
|
||||
return contentSize;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// FUItemCell.h
|
||||
// FUCommonUIComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/24.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUItemCell : UICollectionViewCell
|
||||
|
||||
@property (nonatomic, strong, readonly) UIImageView *imageView;
|
||||
|
||||
@property (nonatomic, strong, readonly) UIActivityIndicatorView *indicatorView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// FUItemCell.m
|
||||
// FUCommonUIComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/24.
|
||||
//
|
||||
|
||||
#import "FUItemCell.h"
|
||||
|
||||
@interface FUItemCell ()
|
||||
|
||||
@property (nonatomic, strong) UIImageView *imageView;
|
||||
|
||||
@property (nonatomic, strong) UIActivityIndicatorView *indicatorView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUItemCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self.contentView addSubview:self.imageView];
|
||||
NSLayoutConstraint *imageLeading = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
|
||||
NSLayoutConstraint *imageTrailing = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
|
||||
NSLayoutConstraint *imageTop = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
|
||||
NSLayoutConstraint *imageBottom = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
|
||||
[self.contentView addConstraints:@[imageLeading, imageTrailing, imageTop, imageBottom]];
|
||||
|
||||
[self.contentView addSubview:self.indicatorView];
|
||||
NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:self.indicatorView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
|
||||
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:self.indicatorView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
|
||||
[self.contentView addConstraints:@[centerXConstraint, centerYConstraint]];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setSelected:(BOOL)selected {
|
||||
[super setSelected:selected];
|
||||
self.imageView.layer.borderWidth = selected ? 3.f : 0;
|
||||
self.imageView.layer.borderColor = selected ? [UIColor colorWithRed:103/255.f green:195/255.f blue:103/255.f alpha:1].CGColor : [UIColor clearColor].CGColor;
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UIImageView *)imageView {
|
||||
if (!_imageView) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_imageView.layer.masksToBounds = YES;
|
||||
_imageView.layer.cornerRadius = 30.f;
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (UIActivityIndicatorView *)indicatorView {
|
||||
if (!_indicatorView) {
|
||||
_indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
|
||||
_indicatorView.hidden = YES;
|
||||
_indicatorView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
}
|
||||
return _indicatorView;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// FUItemsView.h
|
||||
// FUCommonUIComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/24.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class FUItemsView;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol FUItemsViewDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
- (void)itemsView:(FUItemsView *)itemsView didSelectItemAtIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUItemsView : UIView
|
||||
|
||||
/// 数据源
|
||||
/// @discussion 外部传入的icon名数组,查找不到icon会展示空白
|
||||
@property (nonatomic, copy) NSArray<NSString *> *items;
|
||||
|
||||
/// 当前选中索引
|
||||
/// @discussion 默认为 -1,-1为取消选中
|
||||
@property (nonatomic, assign) NSInteger selectedIndex;
|
||||
|
||||
@property (nonatomic, weak) id<FUItemsViewDelegate> delegate;
|
||||
|
||||
/// 初始化
|
||||
/// @param frame Frame
|
||||
/// @param topSpacing 顶部预留空间,默认为0
|
||||
- (instancetype)initWithFrame:(CGRect)frame topSpacing:(CGFloat)topSpacing;
|
||||
|
||||
/// 开始当前选中项动画
|
||||
/// @note 开始动画后无法选择其他项
|
||||
- (void)startAnimation;
|
||||
|
||||
/// 结束当前选中项动画
|
||||
/// @note 结束动画后可以继续选择其他项
|
||||
- (void)stopAnimation;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,197 @@
|
||||
//
|
||||
// FUItemsView.m
|
||||
// FUCommonUIComponent
|
||||
//
|
||||
// Created by 项林平 on 2022/6/24.
|
||||
//
|
||||
|
||||
#import "FUItemsView.h"
|
||||
#import "FUItemCell.h"
|
||||
|
||||
static NSString * const kFUItemCellIdentifier = @"FUItemCell";
|
||||
|
||||
@interface FUItemsView ()<UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
|
||||
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
|
||||
@property (nonatomic, assign) CGFloat collectionTopConstant;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUItemsView
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame topSpacing:(CGFloat)topSpacing {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.collectionTopConstant = topSpacing;
|
||||
[self configureUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self configureUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self configureUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - UI
|
||||
|
||||
- (void)configureUI {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
|
||||
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
|
||||
UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
|
||||
effectView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self addSubview:effectView];
|
||||
NSLayoutConstraint *effectLeading = [NSLayoutConstraint constraintWithItem:effectView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
|
||||
NSLayoutConstraint *effectTrailing = [NSLayoutConstraint constraintWithItem:effectView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
|
||||
NSLayoutConstraint *effectTop = [NSLayoutConstraint constraintWithItem:effectView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
|
||||
NSLayoutConstraint *effectBottom = [NSLayoutConstraint constraintWithItem:effectView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
|
||||
[self addConstraints:@[effectLeading, effectTrailing, effectTop, effectBottom]];
|
||||
|
||||
[self addSubview:self.collectionView];
|
||||
NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:self.collectionView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
|
||||
NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:self.collectionView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
|
||||
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:self.collectionView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:self.collectionTopConstant];
|
||||
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:self.collectionView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:84];
|
||||
[self addConstraints:@[leading, trailing, top]];
|
||||
[self.collectionView addConstraint:height];
|
||||
|
||||
_selectedIndex = -1;
|
||||
}
|
||||
|
||||
#pragma mark - Instance methods
|
||||
|
||||
- (void)startAnimation {
|
||||
if (_selectedIndex < 0 && _selectedIndex >= self.items.count) {
|
||||
return;
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
FUItemCell *selectedCell = (FUItemCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.selectedIndex inSection:0]];
|
||||
if (selectedCell) {
|
||||
[selectedCell.indicatorView startAnimating];
|
||||
self.collectionView.userInteractionEnabled = NO;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)stopAnimation {
|
||||
if (_selectedIndex < 0 && _selectedIndex >= self.items.count) {
|
||||
return;
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
FUItemCell *selectedCell = (FUItemCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:self.selectedIndex inSection:0]];
|
||||
if (selectedCell) {
|
||||
[selectedCell.indicatorView stopAnimating];
|
||||
self.collectionView.userInteractionEnabled = YES;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Private methods
|
||||
|
||||
- (UIImage *)imageWithImageName:(NSString *)imageName {
|
||||
UIImage *resultImage = [UIImage imageNamed:imageName];
|
||||
if (!resultImage) {
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:imageName ofType:@"png"];
|
||||
resultImage = [UIImage imageWithContentsOfFile:path];
|
||||
}
|
||||
if (!resultImage) {
|
||||
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]];
|
||||
resultImage = [UIImage imageWithContentsOfFile:path];
|
||||
}
|
||||
return resultImage;
|
||||
}
|
||||
|
||||
#pragma mark - Collection view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.items.count;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FUItemCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kFUItemCellIdentifier forIndexPath:indexPath];
|
||||
NSString *item = self.items[indexPath.item];
|
||||
cell.imageView.image = [self imageWithImageName:item];
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Collection view delegate
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (indexPath.item == _selectedIndex) {
|
||||
return;
|
||||
}
|
||||
_selectedIndex = indexPath.item;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(itemsView:didSelectItemAtIndex:)]) {
|
||||
[self.delegate itemsView:self didSelectItemAtIndex:indexPath.item];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Collection view delegate flow layout
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return CGSizeMake(60, 60);
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
|
||||
return UIEdgeInsetsMake(12, 16, 12, 16);
|
||||
}
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setItems:(NSArray<NSString *> *)items {
|
||||
_items = items;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.collectionView reloadData];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setSelectedIndex:(NSInteger)selectedIndex {
|
||||
if (selectedIndex < 0 || selectedIndex >= self.items.count) {
|
||||
return;
|
||||
}
|
||||
_selectedIndex = selectedIndex;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:selectedIndex inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(itemsView:didSelectItemAtIndex:)]) {
|
||||
[self.delegate itemsView:self didSelectItemAtIndex:selectedIndex];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UICollectionView *)collectionView {
|
||||
if (!_collectionView) {
|
||||
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
|
||||
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
|
||||
_collectionView.backgroundColor = [UIColor clearColor];
|
||||
_collectionView.showsHorizontalScrollIndicator = NO;
|
||||
_collectionView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.delegate = self;
|
||||
[_collectionView registerClass:[FUItemCell class] forCellWithReuseIdentifier:kFUItemCellIdentifier];
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// FUSegmentBar.h
|
||||
// FULiveDemo
|
||||
//
|
||||
// Created by 项林平 on 2021/9/26.
|
||||
// Copyright © 2021 FaceUnity. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class FUSegmentBar;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol FUSegmentBarDelegate <NSObject>
|
||||
|
||||
- (void)segmentBar:(FUSegmentBar *)segmentBar didSelectItemAtIndex:(NSUInteger)index;
|
||||
|
||||
@optional
|
||||
- (BOOL)segmentBar:(FUSegmentBar *)segmentBar shouldSelectItemAtIndex:(NSInteger)index;
|
||||
|
||||
- (BOOL)segmentBar:(FUSegmentBar *)segmentBar shouldDisableItemAtIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUSegmentBarConfigurations : NSObject
|
||||
|
||||
/// 普通颜色
|
||||
@property (nonatomic, strong) UIColor *normalTitleColor;
|
||||
/// 选中状态颜色
|
||||
@property (nonatomic, strong) UIColor *selectedTitleColor;
|
||||
/// 无法选中状态颜色
|
||||
@property (nonatomic, strong) UIColor *disabledTitleColor;
|
||||
/// 字体
|
||||
@property (nonatomic, strong) UIFont *titleFont;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUSegmentBar : UIView
|
||||
|
||||
@property (nonatomic, weak) id<FUSegmentBarDelegate> delegate;
|
||||
|
||||
/// 当前选中项索引
|
||||
/// @discussion 默认为-1,-1为取消选中
|
||||
@property (nonatomic, assign, readonly) NSInteger selectedIndex;
|
||||
|
||||
/// Unavailable initializer
|
||||
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
|
||||
|
||||
/// 初始化
|
||||
/// @param frame frame
|
||||
/// @param titles SegmentsTitle数组
|
||||
/// @param configuration 配置信息
|
||||
- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray<NSString *> *)titles configuration:(nullable FUSegmentBarConfigurations *)configuration;
|
||||
|
||||
/// 选中指定索引项
|
||||
/// @param index 索引
|
||||
- (void)selectItemAtIndex:(NSInteger)index;
|
||||
|
||||
- (void)refresh;
|
||||
|
||||
@end
|
||||
|
||||
@interface FUSegmentsBarCell : UICollectionViewCell
|
||||
|
||||
@property (nonatomic, strong) UILabel *segmentTitleLabel;
|
||||
@property (nonatomic, strong) UIColor *segmentNormalTitleColor;
|
||||
@property (nonatomic, strong) UIColor *segmentSelectedTitleColor;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,237 @@
|
||||
//
|
||||
// FUSegmentBar.m
|
||||
// FULiveDemo
|
||||
//
|
||||
// Created by 项林平 on 2021/9/26.
|
||||
// Copyright © 2021 FaceUnity. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FUSegmentBar.h"
|
||||
|
||||
@interface FUSegmentBar ()
|
||||
|
||||
@property (nonatomic, assign) NSInteger selectedIndex;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUSegmentBarConfigurations
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
// 默认选中/未选中颜色
|
||||
self.selectedTitleColor = [UIColor colorWithRed:103/255.0f green:195/255.0f blue:103/255.0f alpha:1.0];
|
||||
self.normalTitleColor = [UIColor whiteColor];
|
||||
self.disabledTitleColor = [UIColor colorWithWhite:1 alpha:0.6];
|
||||
self.titleFont = [UIFont systemFontOfSize:13];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static NSString * const kFUSegmentCellIdentifierKey = @"FUSegmentCellIdentifier";
|
||||
|
||||
@interface FUSegmentBar ()<UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
|
||||
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
|
||||
@property (nonatomic, strong) FUSegmentBarConfigurations *configuration;
|
||||
@property (nonatomic, strong) NSMutableArray *titles;
|
||||
|
||||
/// cell宽度数组
|
||||
@property (nonatomic, copy) NSArray *itemWidths;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUSegmentBar
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray<NSString *> *)titles configuration:(FUSegmentBarConfigurations *)configuration {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.backgroundColor = [UIColor colorWithRed:5/255.0 green:15/255.0 blue:20/255.0 alpha:1.0];
|
||||
self.titles = [titles mutableCopy];
|
||||
self.configuration = configuration;
|
||||
if (!self.configuration) {
|
||||
self.configuration = [[FUSegmentBarConfigurations alloc] init];
|
||||
}
|
||||
|
||||
// 计算宽度
|
||||
NSMutableArray *tempWidths = [NSMutableArray arrayWithCapacity:self.titles.count];
|
||||
if (self.titles.count < 7) {
|
||||
// 平均分配宽度
|
||||
CGFloat width = CGRectGetWidth(frame) / self.titles.count * 1.0;
|
||||
for (NSInteger i = 0; i < self.titles.count; i++) {
|
||||
[tempWidths addObject:@(width)];
|
||||
}
|
||||
} else {
|
||||
// 根据文字适配宽度
|
||||
for (NSString *title in self.titles) {
|
||||
CGSize nameSize = [title sizeWithAttributes:@{NSFontAttributeName : self.configuration.titleFont}];
|
||||
[tempWidths addObject:@(nameSize.width + 20)];
|
||||
}
|
||||
}
|
||||
self.itemWidths = [tempWidths copy];
|
||||
|
||||
_selectedIndex = -1;
|
||||
|
||||
[self addSubview:self.collectionView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Instance methods
|
||||
|
||||
- (void)selectItemAtIndex:(NSInteger)index {
|
||||
NSInteger count = self.titles.count;
|
||||
if (index >= count) {
|
||||
return;
|
||||
}
|
||||
if (self.selectedIndex == index) {
|
||||
// 目标索引和当前选中索引相同时,不需要处理界面逻辑,只要触发回调即可
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(segmentBar:didSelectItemAtIndex:)]) {
|
||||
[self.delegate segmentBar:self didSelectItemAtIndex:index];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (index == -1) {
|
||||
// 取消选中时只需要更新界面
|
||||
[self.collectionView deselectItemAtIndexPath:[NSIndexPath indexPathForItem:self.selectedIndex inSection:0] animated:NO];
|
||||
self.selectedIndex = -1;
|
||||
} else {
|
||||
// 正常选中需要处理界面逻辑并触发回调
|
||||
[self.collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(segmentBar:didSelectItemAtIndex:)]) {
|
||||
[self.delegate segmentBar:self didSelectItemAtIndex:index];
|
||||
}
|
||||
self.selectedIndex = index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)refresh {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.collectionView reloadData];
|
||||
if (self.selectedIndex >= 0) {
|
||||
[self.collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:self.selectedIndex inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Collection view data source
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.titles.count;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FUSegmentsBarCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kFUSegmentCellIdentifierKey forIndexPath:indexPath];
|
||||
cell.segmentTitleLabel.text = self.titles[indexPath.item];
|
||||
cell.segmentTitleLabel.font = self.configuration.titleFont;
|
||||
cell.segmentNormalTitleColor = self.configuration.normalTitleColor;
|
||||
cell.segmentSelectedTitleColor = self.configuration.selectedTitleColor;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(segmentBar:shouldDisableItemAtIndex:)]) {
|
||||
if ([self.delegate segmentBar:self shouldDisableItemAtIndex:indexPath.item]) {
|
||||
cell.segmentTitleLabel.textColor = self.configuration.disabledTitleColor;
|
||||
}
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Collection view delegate
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
_selectedIndex = indexPath.item;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(segmentBar:didSelectItemAtIndex:)]) {
|
||||
[self.delegate segmentBar:self didSelectItemAtIndex:indexPath.item];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(segmentBar:shouldSelectItemAtIndex:)]) {
|
||||
return [self.delegate segmentBar:self shouldSelectItemAtIndex:indexPath.item];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Collection view delegate flow layout
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return CGSizeMake([self.itemWidths[indexPath.item] floatValue], CGRectGetHeight(collectionView.frame));
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
|
||||
return UIEdgeInsetsZero;
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UICollectionView *)collectionView {
|
||||
if (!_collectionView) {
|
||||
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
|
||||
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.frame), 49.f) collectionViewLayout:flowLayout];
|
||||
_collectionView.backgroundColor = [UIColor clearColor];
|
||||
_collectionView.showsHorizontalScrollIndicator = NO;
|
||||
_collectionView.showsVerticalScrollIndicator = NO;
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.delegate = self;
|
||||
|
||||
[_collectionView registerClass:[FUSegmentsBarCell class] forCellWithReuseIdentifier:kFUSegmentCellIdentifierKey];
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUSegmentsBarCell
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
[self.contentView addSubview:self.segmentTitleLabel];
|
||||
NSLayoutConstraint *titleLabelCenterX = [NSLayoutConstraint constraintWithItem:self.segmentTitleLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
|
||||
NSLayoutConstraint *titleLabelCenterY = [NSLayoutConstraint constraintWithItem:self.segmentTitleLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
|
||||
[self.contentView addConstraints:@[titleLabelCenterX, titleLabelCenterY]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setSelected:(BOOL)selected {
|
||||
[super setSelected:selected];
|
||||
if (selected) {
|
||||
self.segmentTitleLabel.textColor = self.segmentSelectedTitleColor ? self.segmentSelectedTitleColor : [UIColor colorWithRed:103/255.0f green:195/255.0f blue:103/255.0f alpha:1.0];
|
||||
} else {
|
||||
self.segmentTitleLabel.textColor = self.segmentNormalTitleColor ? self.segmentNormalTitleColor : [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UILabel *)segmentTitleLabel {
|
||||
if (!_segmentTitleLabel) {
|
||||
_segmentTitleLabel = [[UILabel alloc] initWithFrame:self.contentView.bounds];
|
||||
_segmentTitleLabel.textColor = [UIColor whiteColor];
|
||||
_segmentTitleLabel.font = [UIFont systemFontOfSize:13];
|
||||
_segmentTitleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_segmentTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
}
|
||||
return _segmentTitleLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// FUSlider.h
|
||||
// FUAPIDemoBar
|
||||
//
|
||||
// Created by L on 2018/6/27.
|
||||
// Copyright © 2018年 L. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface FUSlider : UISlider
|
||||
|
||||
/// 零点是否在中间,默认为NO
|
||||
@property (nonatomic, assign, getter=isBidirection) BOOL bidirection;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// FUSlider.m
|
||||
// FUAPIDemoBar
|
||||
//
|
||||
// Created by L on 2018/6/27.
|
||||
// Copyright © 2018年 L. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FUSlider.h"
|
||||
#import "FUCommonUIDefine.h"
|
||||
|
||||
@interface FUSlider ()
|
||||
|
||||
/// 当前值提示标签
|
||||
@property (nonatomic, strong) UILabel *tipLabel;
|
||||
/// 当前值提示标签背景
|
||||
@property (nonatomic, strong) UIImageView *tipBackgroundImageView;
|
||||
/// 零点在中间时自定义视图
|
||||
@property (nonatomic, strong) UIView *trackView;
|
||||
/// 零点在中间时的中间短线
|
||||
@property (nonatomic, strong) UIView *middleLine;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUSlider
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
[self configureUI];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self configureUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIView *)sliderTrackBackView {
|
||||
return self.subviews.firstObject;
|
||||
}
|
||||
|
||||
- (void)configureUI {
|
||||
[self setThumbImage:FUCommonUIImageNamed(@"slider_dot") forState:UIControlStateNormal];
|
||||
[self setMaximumTrackTintColor:[UIColor whiteColor]];
|
||||
[self setMinimumTrackTintColor:[UIColor colorWithRed:103/255.0 green:195/255.0 blue:103/255.0 alpha:1]];
|
||||
[self addSubview:self.tipBackgroundImageView];
|
||||
[self addSubview:self.tipLabel];
|
||||
[self.sliderTrackBackView addSubview:self.trackView];
|
||||
[self addSubview:self.middleLine];
|
||||
}
|
||||
|
||||
-(void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
if (!self.trackView.hidden) {
|
||||
[self.sliderTrackBackView insertSubview:self.trackView atIndex:self.subviews.count-2];
|
||||
// [self bringSubviewToFront:self.trackView];
|
||||
}
|
||||
if (!self.middleLine.hidden) {
|
||||
self.middleLine.frame = CGRectMake(CGRectGetWidth(self.bounds)/2.0 - 1, CGRectGetHeight(self.bounds)/2.0 - 4, 2, 8);
|
||||
}
|
||||
[self setValue:self.value animated:NO];
|
||||
}
|
||||
|
||||
- (void)setBidirection:(BOOL)bidirection {
|
||||
_bidirection = bidirection;
|
||||
if (bidirection) {
|
||||
self.middleLine.hidden = NO;
|
||||
self.trackView.hidden = NO;
|
||||
[self setMinimumTrackTintColor:[UIColor whiteColor]];
|
||||
} else {
|
||||
self.middleLine.hidden = YES;
|
||||
self.trackView.hidden = YES;
|
||||
[self setMinimumTrackTintColor:[UIColor colorWithRed:103/255.0 green:195/255.0 blue:103/255.0 alpha:1]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setValue:(float)value animated:(BOOL)animated {
|
||||
[super setValue:value animated:animated];
|
||||
|
||||
if (_bidirection) {
|
||||
self.tipLabel.text = [NSString stringWithFormat:@"%d",(int)(value * 100 - 50)];
|
||||
CGFloat currentValue = value - 0.5;
|
||||
CGFloat width = currentValue * CGRectGetWidth(self.bounds);
|
||||
if (width < 0 ) {
|
||||
width = -width;
|
||||
}
|
||||
CGFloat originX = currentValue > 0 ? CGRectGetWidth(self.bounds) / 2.0 : CGRectGetWidth(self.bounds) / 2.0 - width;
|
||||
self.trackView.frame = CGRectMake(originX, CGRectGetHeight(self.frame)/2.0 - 2, width, 4.0);
|
||||
} else {
|
||||
self.tipLabel.text = [NSString stringWithFormat:@"%d",(int)(value * 100)];
|
||||
}
|
||||
CGFloat x = value * (self.frame.size.width - 16) - self.tipLabel.frame.size.width * 0.5 + 8;
|
||||
CGRect frame = self.tipLabel.frame;
|
||||
frame.origin.x = x;
|
||||
|
||||
self.tipBackgroundImageView.frame = frame;
|
||||
self.tipLabel.frame = frame;
|
||||
self.tipLabel.hidden = !self.isTouchInside;
|
||||
self.tipBackgroundImageView.hidden = !self.isTouchInside;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UIImageView *)tipBackgroundImageView {
|
||||
if (!_tipBackgroundImageView) {
|
||||
UIImage *bgImage = FUCommonUIImageNamed(@"slider_tip_background");
|
||||
_tipBackgroundImageView = [[UIImageView alloc] initWithImage:bgImage];
|
||||
_tipBackgroundImageView.frame = CGRectMake(0, -bgImage.size.height, bgImage.size.width, bgImage.size.height);
|
||||
_tipBackgroundImageView.hidden = YES;
|
||||
}
|
||||
return _tipBackgroundImageView;
|
||||
}
|
||||
- (UILabel *)tipLabel {
|
||||
if (!_tipLabel) {
|
||||
_tipLabel = [[UILabel alloc] initWithFrame:self.tipBackgroundImageView.frame];
|
||||
_tipLabel.textColor = [UIColor whiteColor];
|
||||
_tipLabel.font = [UIFont systemFontOfSize:10 weight:UIFontWeightMedium];
|
||||
_tipLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_tipLabel.hidden = YES;
|
||||
}
|
||||
return _tipLabel;
|
||||
}
|
||||
|
||||
- (UIView *)trackView {
|
||||
if (!_trackView) {
|
||||
_trackView = [[UIView alloc] init];
|
||||
_trackView.backgroundColor = [UIColor colorWithRed:103/255.f green:195/255.f blue:103/255.f alpha:1];
|
||||
_trackView.hidden = YES;
|
||||
}
|
||||
return _trackView;
|
||||
}
|
||||
|
||||
- (UIView *)middleLine {
|
||||
if (!_middleLine) {
|
||||
_middleLine = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds)/2.0 - 1, CGRectGetHeight(self.bounds)/2.0 - 4, 2, 8)];
|
||||
_middleLine.backgroundColor = [UIColor whiteColor];
|
||||
_middleLine.layer.masksToBounds = YES;
|
||||
_middleLine.layer.cornerRadius = 1.0;
|
||||
_middleLine.hidden = YES;
|
||||
}
|
||||
return _middleLine;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// FUSquareButton.h
|
||||
// FULive
|
||||
//
|
||||
// Created by 孙慕 on 2018/8/28.
|
||||
// Copyright © 2018年 L. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface FUSquareButton : UIButton
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame interval:(float)interval;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// FUSquareButton.m
|
||||
// FULive
|
||||
//
|
||||
// Created by 孙慕 on 2018/8/28.
|
||||
// Copyright © 2018年 L. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FUSquareButton.h"
|
||||
|
||||
@interface FUSquareButton()
|
||||
|
||||
@property(nonatomic,assign) float interval;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FUSquareButton
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame interval:(float)interval{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
_interval = interval;
|
||||
self.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
self.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
_interval = 8;
|
||||
self.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
self.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super initWithCoder:aDecoder]) {
|
||||
_interval = 8;
|
||||
self.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
self.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
CGRect frame = self.imageView.bounds;
|
||||
CGRect frame1 = self.titleLabel.frame;
|
||||
|
||||
self.imageView.frame = frame;
|
||||
CGPoint center = self.imageView.center;
|
||||
center.x = self.frame.size.width * 0.5;
|
||||
self.imageView.center = center;
|
||||
frame1.origin.x = 0;
|
||||
frame1.origin.y = CGRectGetMaxY(self.imageView.frame) + _interval;
|
||||
frame1.size.height = 14;
|
||||
frame1.size.width = self.bounds.size.width;;
|
||||
self.titleLabel.frame = frame1;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// FUTipHUD.h
|
||||
// FULiveDemo
|
||||
//
|
||||
// Created by 项林平 on 2021/4/12.
|
||||
// Copyright © 2021 FaceUnity. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FUTipHUDPosition) {
|
||||
FUTipHUDPositionTop,
|
||||
FUTipHUDPositionCenter
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FUTipHUD : NSObject
|
||||
|
||||
/// 文字提示(默认3秒后自动消失)
|
||||
/// @param tipsString 文字
|
||||
+ (void)showTips:(NSString *)tipsString;
|
||||
|
||||
/// 文字提示
|
||||
/// @param tipsString 文字
|
||||
/// @param delay 自动消失时间,单位: 秒
|
||||
+ (void)showTips:(NSString *)tipsString dismissWithDelay:(NSTimeInterval)delay;
|
||||
|
||||
/// 文字提示
|
||||
/// @param tipsString 文字
|
||||
/// @param delay 自动消失时间,单位: 秒
|
||||
/// @param position 显示位置,默认为FUTipHUDPositionTop
|
||||
+ (void)showTips:(NSString *)tipsString dismissWithDelay:(NSTimeInterval)delay position:(FUTipHUDPosition)position;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// FUTipHUD.m
|
||||
// FULiveDemo
|
||||
//
|
||||
// Created by 项林平 on 2021/4/12.
|
||||
// Copyright © 2021 FaceUnity. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FUTipHUD.h"
|
||||
#import "FUInsetsLabel.h"
|
||||
|
||||
@implementation FUTipHUD
|
||||
|
||||
+ (void)showTips:(NSString *)tipsString {
|
||||
[self showTips:tipsString dismissWithDelay:3];
|
||||
}
|
||||
|
||||
+ (void)showTips:(NSString *)tipsString dismissWithDelay:(NSTimeInterval)delay {
|
||||
[self showTips:tipsString dismissWithDelay:delay position:FUTipHUDPositionTop];
|
||||
}
|
||||
|
||||
+ (void)showTips:(NSString *)tipsString dismissWithDelay:(NSTimeInterval)delay position:(FUTipHUDPosition)position {
|
||||
UIWindow *window = [UIApplication sharedApplication].delegate.window;
|
||||
// 避免重复生成label
|
||||
NSArray<UIView *> *views = window.subviews;
|
||||
[views enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if ([obj isMemberOfClass:[FUInsetsLabel class]]) {
|
||||
[obj removeFromSuperview];
|
||||
obj = nil;
|
||||
}
|
||||
}];
|
||||
|
||||
__block FUInsetsLabel *tipLabel = [[FUInsetsLabel alloc] initWithFrame:CGRectZero insets:UIEdgeInsetsMake(8, 20, 8, 20)];
|
||||
tipLabel.backgroundColor = [UIColor colorWithRed:5/255.0 green:15/255.0 blue:20/255.0 alpha:0.74];
|
||||
tipLabel.textColor = [UIColor whiteColor];
|
||||
tipLabel.font = [UIFont systemFontOfSize:13];
|
||||
tipLabel.numberOfLines = 0;
|
||||
tipLabel.layer.masksToBounds = YES;
|
||||
tipLabel.layer.cornerRadius = 4;
|
||||
tipLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
tipLabel.text = tipsString;
|
||||
[window addSubview:tipLabel];
|
||||
|
||||
if (position == FUTipHUDPositionTop) {
|
||||
CGFloat topConstant = 0;
|
||||
if (@available(iOS 11.0, *)) {
|
||||
topConstant = window.safeAreaInsets.top;
|
||||
}
|
||||
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:tipLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:window attribute:NSLayoutAttributeTop multiplier:1 constant:84 + topConstant];
|
||||
[window addConstraint:topConstraint];
|
||||
} else {
|
||||
NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:tipLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:window attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
|
||||
[window addConstraint:centerYConstraint];
|
||||
}
|
||||
CGFloat windowWidth = CGRectGetWidth(window.bounds);
|
||||
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:tipLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:windowWidth - 40];
|
||||
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:tipLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:window attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
|
||||
[window addConstraint:centerXConstraint];
|
||||
[tipLabel addConstraint:widthConstraint];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
tipLabel.alpha = 0;
|
||||
} completion:^(BOOL finished) {
|
||||
[tipLabel removeFromSuperview];
|
||||
tipLabel = nil;
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "slider_dot.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "slider_dot@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "slider_dot@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 191 B |
Binary file not shown.
|
After Width: | Height: | Size: 485 B |
Binary file not shown.
|
After Width: | Height: | Size: 1009 B |
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "slider_tip_background.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "slider_tip_background@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "slider_tip_background@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 783 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
3
Example/SubModules/FUCommonUIComponent/README.md
Normal file
3
Example/SubModules/FUCommonUIComponent/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# FUCommonUIComponent
|
||||
|
||||
通用UI组件
|
||||
BIN
Example/SubModules/FURenderKit/.DS_Store
vendored
Normal file
BIN
Example/SubModules/FURenderKit/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,628 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
25D108CE056FDC71944B8D96 /* Pods_FURenderKit_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DE66819F43636C81BFA273B /* Pods_FURenderKit_Example.framework */; };
|
||||
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
|
||||
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
|
||||
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
|
||||
6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; };
|
||||
6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; };
|
||||
6003F59E195388D20070C39A /* CALEBAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* CALEBAppDelegate.m */; };
|
||||
6003F5A7195388D20070C39A /* CALEBViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5A6195388D20070C39A /* CALEBViewController.m */; };
|
||||
6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; };
|
||||
6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
|
||||
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
|
||||
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
|
||||
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
|
||||
6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; };
|
||||
71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; };
|
||||
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
|
||||
938CD1392A2747472CD1D0B6 /* Pods_FURenderKit_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F73A65B7B681BAD128B0C55A /* Pods_FURenderKit_Tests.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
6003F5B3195388D20070C39A /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 6003F582195388D10070C39A /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 6003F589195388D20070C39A;
|
||||
remoteInfo = FURenderKit;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
16328503CF7647332B00EB76 /* Pods-FURenderKit_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FURenderKit_Example.debug.xcconfig"; path = "Target Support Files/Pods-FURenderKit_Example/Pods-FURenderKit_Example.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
3DE66819F43636C81BFA273B /* Pods_FURenderKit_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FURenderKit_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
403E0382A57DE0A2174B1A32 /* Pods-FURenderKit_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FURenderKit_Tests.debug.xcconfig"; path = "Target Support Files/Pods-FURenderKit_Tests/Pods-FURenderKit_Tests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
5D7DB92367728FD88D73BA2D /* FURenderKit.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = FURenderKit.podspec; path = ../FURenderKit.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
|
||||
6003F58A195388D20070C39A /* FURenderKit_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FURenderKit_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||
6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
6003F595195388D20070C39A /* FURenderKit-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "FURenderKit-Info.plist"; sourceTree = "<group>"; };
|
||||
6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
6003F59B195388D20070C39A /* FURenderKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FURenderKit-Prefix.pch"; sourceTree = "<group>"; };
|
||||
6003F59C195388D20070C39A /* CALEBAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CALEBAppDelegate.h; sourceTree = "<group>"; };
|
||||
6003F59D195388D20070C39A /* CALEBAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CALEBAppDelegate.m; sourceTree = "<group>"; };
|
||||
6003F5A5195388D20070C39A /* CALEBViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CALEBViewController.h; sourceTree = "<group>"; };
|
||||
6003F5A6195388D20070C39A /* CALEBViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CALEBViewController.m; sourceTree = "<group>"; };
|
||||
6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
6003F5AE195388D20070C39A /* FURenderKit_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FURenderKit_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
|
||||
6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; };
|
||||
6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = "<group>"; };
|
||||
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; };
|
||||
71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
7DDD0571106B74DD57603351 /* Pods-FURenderKit_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FURenderKit_Tests.release.xcconfig"; path = "Target Support Files/Pods-FURenderKit_Tests/Pods-FURenderKit_Tests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
B4A9EEC998BB33EDC1011552 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
|
||||
D2AC8D5C01FEE0E1C47CF521 /* Pods-FURenderKit_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FURenderKit_Example.release.xcconfig"; path = "Target Support Files/Pods-FURenderKit_Example/Pods-FURenderKit_Example.release.xcconfig"; sourceTree = "<group>"; };
|
||||
EF6578F88748EF764D8A0E2C /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
|
||||
F73A65B7B681BAD128B0C55A /* Pods_FURenderKit_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FURenderKit_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
6003F587195388D20070C39A /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */,
|
||||
6003F592195388D20070C39A /* UIKit.framework in Frameworks */,
|
||||
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */,
|
||||
25D108CE056FDC71944B8D96 /* Pods_FURenderKit_Example.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
6003F5AB195388D20070C39A /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */,
|
||||
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */,
|
||||
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */,
|
||||
938CD1392A2747472CD1D0B6 /* Pods_FURenderKit_Tests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
6003F581195388D10070C39A = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
60FF7A9C1954A5C5007DD14C /* Podspec Metadata */,
|
||||
6003F593195388D20070C39A /* Example for FURenderKit */,
|
||||
6003F5B5195388D20070C39A /* Tests */,
|
||||
6003F58C195388D20070C39A /* Frameworks */,
|
||||
6003F58B195388D20070C39A /* Products */,
|
||||
A2FD88596E1021E2ED41BA65 /* Pods */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6003F58B195388D20070C39A /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6003F58A195388D20070C39A /* FURenderKit_Example.app */,
|
||||
6003F5AE195388D20070C39A /* FURenderKit_Tests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6003F58C195388D20070C39A /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6003F58D195388D20070C39A /* Foundation.framework */,
|
||||
6003F58F195388D20070C39A /* CoreGraphics.framework */,
|
||||
6003F591195388D20070C39A /* UIKit.framework */,
|
||||
6003F5AF195388D20070C39A /* XCTest.framework */,
|
||||
3DE66819F43636C81BFA273B /* Pods_FURenderKit_Example.framework */,
|
||||
F73A65B7B681BAD128B0C55A /* Pods_FURenderKit_Tests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6003F593195388D20070C39A /* Example for FURenderKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6003F59C195388D20070C39A /* CALEBAppDelegate.h */,
|
||||
6003F59D195388D20070C39A /* CALEBAppDelegate.m */,
|
||||
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */,
|
||||
6003F5A5195388D20070C39A /* CALEBViewController.h */,
|
||||
6003F5A6195388D20070C39A /* CALEBViewController.m */,
|
||||
71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */,
|
||||
6003F5A8195388D20070C39A /* Images.xcassets */,
|
||||
6003F594195388D20070C39A /* Supporting Files */,
|
||||
);
|
||||
name = "Example for FURenderKit";
|
||||
path = FURenderKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6003F594195388D20070C39A /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6003F595195388D20070C39A /* FURenderKit-Info.plist */,
|
||||
6003F596195388D20070C39A /* InfoPlist.strings */,
|
||||
6003F599195388D20070C39A /* main.m */,
|
||||
6003F59B195388D20070C39A /* FURenderKit-Prefix.pch */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6003F5B5195388D20070C39A /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6003F5BB195388D20070C39A /* Tests.m */,
|
||||
6003F5B6195388D20070C39A /* Supporting Files */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6003F5B6195388D20070C39A /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6003F5B7195388D20070C39A /* Tests-Info.plist */,
|
||||
6003F5B8195388D20070C39A /* InfoPlist.strings */,
|
||||
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D7DB92367728FD88D73BA2D /* FURenderKit.podspec */,
|
||||
EF6578F88748EF764D8A0E2C /* README.md */,
|
||||
B4A9EEC998BB33EDC1011552 /* LICENSE */,
|
||||
);
|
||||
name = "Podspec Metadata";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A2FD88596E1021E2ED41BA65 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
16328503CF7647332B00EB76 /* Pods-FURenderKit_Example.debug.xcconfig */,
|
||||
D2AC8D5C01FEE0E1C47CF521 /* Pods-FURenderKit_Example.release.xcconfig */,
|
||||
403E0382A57DE0A2174B1A32 /* Pods-FURenderKit_Tests.debug.xcconfig */,
|
||||
7DDD0571106B74DD57603351 /* Pods-FURenderKit_Tests.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
6003F589195388D20070C39A /* FURenderKit_Example */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "FURenderKit_Example" */;
|
||||
buildPhases = (
|
||||
63CAF193CF27A4682A308E4D /* [CP] Check Pods Manifest.lock */,
|
||||
6003F586195388D20070C39A /* Sources */,
|
||||
6003F587195388D20070C39A /* Frameworks */,
|
||||
6003F588195388D20070C39A /* Resources */,
|
||||
04234FB4C1CACC9C1F004127 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = FURenderKit_Example;
|
||||
productName = FURenderKit;
|
||||
productReference = 6003F58A195388D20070C39A /* FURenderKit_Example.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
6003F5AD195388D20070C39A /* FURenderKit_Tests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "FURenderKit_Tests" */;
|
||||
buildPhases = (
|
||||
5A56B9B9057B0D35BB0911A6 /* [CP] Check Pods Manifest.lock */,
|
||||
6003F5AA195388D20070C39A /* Sources */,
|
||||
6003F5AB195388D20070C39A /* Frameworks */,
|
||||
6003F5AC195388D20070C39A /* Resources */,
|
||||
765D239FA97D8E8C7588ACA9 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
6003F5B4195388D20070C39A /* PBXTargetDependency */,
|
||||
);
|
||||
name = FURenderKit_Tests;
|
||||
productName = FURenderKitTests;
|
||||
productReference = 6003F5AE195388D20070C39A /* FURenderKit_Tests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
6003F582195388D10070C39A /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
CLASSPREFIX = CALEB;
|
||||
LastUpgradeCheck = 0720;
|
||||
ORGANIZATIONNAME = Caleb;
|
||||
TargetAttributes = {
|
||||
6003F5AD195388D20070C39A = {
|
||||
TestTargetID = 6003F589195388D20070C39A;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 6003F585195388D10070C39A /* Build configuration list for PBXProject "FURenderKit" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 6003F581195388D10070C39A;
|
||||
productRefGroup = 6003F58B195388D20070C39A /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
6003F589195388D20070C39A /* FURenderKit_Example */,
|
||||
6003F5AD195388D20070C39A /* FURenderKit_Tests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
6003F588195388D20070C39A /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */,
|
||||
71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */,
|
||||
6003F5A9195388D20070C39A /* Images.xcassets in Resources */,
|
||||
6003F598195388D20070C39A /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
6003F5AC195388D20070C39A /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
04234FB4C1CACC9C1F004127 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-FURenderKit_Example/Pods-FURenderKit_Example-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/FURenderKit/FURenderKit.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FURenderKit.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FURenderKit_Example/Pods-FURenderKit_Example-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
5A56B9B9057B0D35BB0911A6 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-FURenderKit_Tests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
63CAF193CF27A4682A308E4D /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-FURenderKit_Example-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
765D239FA97D8E8C7588ACA9 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-FURenderKit_Tests/Pods-FURenderKit_Tests-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/Expecta/Expecta.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/Expecta+Snapshots/Expecta_Snapshots.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/Specta/Specta.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Expecta_Snapshots.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSnapshotTestCase.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Specta.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FURenderKit_Tests/Pods-FURenderKit_Tests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
6003F586195388D20070C39A /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6003F59E195388D20070C39A /* CALEBAppDelegate.m in Sources */,
|
||||
6003F5A7195388D20070C39A /* CALEBViewController.m in Sources */,
|
||||
6003F59A195388D20070C39A /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
6003F5AA195388D20070C39A /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6003F5BC195388D20070C39A /* Tests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
6003F5B4195388D20070C39A /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 6003F589195388D20070C39A /* FURenderKit_Example */;
|
||||
targetProxy = 6003F5B3195388D20070C39A /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
6003F596195388D20070C39A /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
6003F597195388D20070C39A /* en */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6003F5B8195388D20070C39A /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
6003F5B9195388D20070C39A /* en */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
71719F9E1E33DC2100824A3D /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
6003F5BD195388D20070C39A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
6003F5BE195388D20070C39A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
6003F5C0195388D20070C39A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 16328503CF7647332B00EB76 /* Pods-FURenderKit_Example.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "FURenderKit/FURenderKit-Prefix.pch";
|
||||
INFOPLIST_FILE = "FURenderKit/FURenderKit-Info.plist";
|
||||
MODULE_NAME = ExampleApp;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
6003F5C1195388D20070C39A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D2AC8D5C01FEE0E1C47CF521 /* Pods-FURenderKit_Example.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "FURenderKit/FURenderKit-Prefix.pch";
|
||||
INFOPLIST_FILE = "FURenderKit/FURenderKit-Info.plist";
|
||||
MODULE_NAME = ExampleApp;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
6003F5C3195388D20070C39A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 403E0382A57DE0A2174B1A32 /* Pods-FURenderKit_Tests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
||||
);
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = "Tests/Tests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FURenderKit_Example.app/FURenderKit_Example";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
6003F5C4195388D20070C39A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7DDD0571106B74DD57603351 /* Pods-FURenderKit_Tests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
||||
);
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch";
|
||||
INFOPLIST_FILE = "Tests/Tests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FURenderKit_Example.app/FURenderKit_Example";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
6003F585195388D10070C39A /* Build configuration list for PBXProject "FURenderKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
6003F5BD195388D20070C39A /* Debug */,
|
||||
6003F5BE195388D20070C39A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "FURenderKit_Example" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
6003F5C0195388D20070C39A /* Debug */,
|
||||
6003F5C1195388D20070C39A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "FURenderKit_Tests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
6003F5C3195388D20070C39A /* Debug */,
|
||||
6003F5C4195388D20070C39A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 6003F582195388D10070C39A /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:FURenderKit.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6003F589195388D20070C39A"
|
||||
BuildableName = "FURenderKit_Example.app"
|
||||
BlueprintName = "FURenderKit_Example"
|
||||
ReferencedContainer = "container:FURenderKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6003F5AD195388D20070C39A"
|
||||
BuildableName = "FURenderKit_Tests.xctest"
|
||||
BlueprintName = "FURenderKit_Tests"
|
||||
ReferencedContainer = "container:FURenderKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6003F589195388D20070C39A"
|
||||
BuildableName = "FURenderKit_Example.app"
|
||||
BlueprintName = "FURenderKit_Example"
|
||||
ReferencedContainer = "container:FURenderKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6003F589195388D20070C39A"
|
||||
BuildableName = "FURenderKit_Example.app"
|
||||
BlueprintName = "FURenderKit_Example"
|
||||
ReferencedContainer = "container:FURenderKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6003F589195388D20070C39A"
|
||||
BuildableName = "FURenderKit_Example.app"
|
||||
BlueprintName = "FURenderKit_Example"
|
||||
ReferencedContainer = "container:FURenderKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
10
Example/SubModules/FURenderKit/Example/FURenderKit.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
Example/SubModules/FURenderKit/Example/FURenderKit.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:FURenderKit.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
Binary file not shown.
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="whP-gf-Uak">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="wQg-tq-qST">
|
||||
<objects>
|
||||
<viewController id="whP-gf-Uak" customClass="CALEBViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="uEw-UM-LJ8"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="Mvr-aV-6Um"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="TpU-gO-2f1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="tc2-Qw-aMS" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="305" y="433"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// CALEBAppDelegate.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Caleb on 08/05/2025.
|
||||
// Copyright (c) 2025 Caleb. All rights reserved.
|
||||
//
|
||||
|
||||
@import UIKit;
|
||||
|
||||
@interface CALEBAppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// CALEBAppDelegate.m
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Caleb on 08/05/2025.
|
||||
// Copyright (c) 2025 Caleb. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CALEBAppDelegate.h"
|
||||
|
||||
@implementation CALEBAppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
// Override point for customization after application launch.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application
|
||||
{
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||
{
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||
{
|
||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application
|
||||
{
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// CALEBViewController.h
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Caleb on 08/05/2025.
|
||||
// Copyright (c) 2025 Caleb. All rights reserved.
|
||||
//
|
||||
|
||||
@import UIKit;
|
||||
|
||||
@interface CALEBViewController : UIViewController
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// CALEBViewController.m
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Caleb on 08/05/2025.
|
||||
// Copyright (c) 2025 Caleb. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CALEBViewController.h"
|
||||
|
||||
@interface CALEBViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation CALEBViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Prefix header
|
||||
//
|
||||
// The contents of this file are implicitly included at the beginning of every source file.
|
||||
//
|
||||
|
||||
#import <Availability.h>
|
||||
|
||||
#ifndef __IPHONE_5_0
|
||||
#warning "This project uses features only available in iOS SDK 5.0 and later."
|
||||
#endif
|
||||
|
||||
#ifdef __OBJC__
|
||||
@import UIKit;
|
||||
@import Foundation;
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
17
Example/SubModules/FURenderKit/Example/FURenderKit/main.m
Normal file
17
Example/SubModules/FURenderKit/Example/FURenderKit/main.m
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// main.m
|
||||
// FURenderKit
|
||||
//
|
||||
// Created by Caleb on 08/05/2025.
|
||||
// Copyright (c) 2025 Caleb. All rights reserved.
|
||||
//
|
||||
|
||||
@import UIKit;
|
||||
#import "CALEBAppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([CALEBAppDelegate class]));
|
||||
}
|
||||
}
|
||||
16
Example/SubModules/FURenderKit/Example/Podfile
Normal file
16
Example/SubModules/FURenderKit/Example/Podfile
Normal file
@@ -0,0 +1,16 @@
|
||||
use_frameworks!
|
||||
|
||||
platform :ios, '10.0'
|
||||
|
||||
target 'FURenderKit_Example' do
|
||||
pod 'FURenderKit', :path => '../'
|
||||
|
||||
target 'FURenderKit_Tests' do
|
||||
inherit! :search_paths
|
||||
|
||||
pod 'Specta'
|
||||
pod 'Expecta'
|
||||
pod 'FBSnapshotTestCase'
|
||||
pod 'Expecta+Snapshots'
|
||||
end
|
||||
end
|
||||
42
Example/SubModules/FURenderKit/Example/Podfile.lock
Normal file
42
Example/SubModules/FURenderKit/Example/Podfile.lock
Normal file
@@ -0,0 +1,42 @@
|
||||
PODS:
|
||||
- Expecta (1.0.6)
|
||||
- "Expecta+Snapshots (3.1.1)":
|
||||
- Expecta (~> 1.0)
|
||||
- FBSnapshotTestCase/Core (~> 2.0)
|
||||
- Specta (~> 1.0)
|
||||
- FBSnapshotTestCase (2.1.4):
|
||||
- FBSnapshotTestCase/SwiftSupport (= 2.1.4)
|
||||
- FBSnapshotTestCase/Core (2.1.4)
|
||||
- FBSnapshotTestCase/SwiftSupport (2.1.4):
|
||||
- FBSnapshotTestCase/Core
|
||||
- FURenderKit (0.1.0)
|
||||
- Specta (1.0.7)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Expecta
|
||||
- "Expecta+Snapshots"
|
||||
- FBSnapshotTestCase
|
||||
- FURenderKit (from `../`)
|
||||
- Specta
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- Expecta
|
||||
- "Expecta+Snapshots"
|
||||
- FBSnapshotTestCase
|
||||
- Specta
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
FURenderKit:
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Expecta: 3b6bd90a64b9a1dcb0b70aa0e10a7f8f631667d5
|
||||
"Expecta+Snapshots": dcff217eef506dabd6dfdc7864ea2da321fafbb8
|
||||
FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
|
||||
FURenderKit: 2ca084d9811616f9bb1936160a57d77acd43357b
|
||||
Specta: 3e1bd89c3517421982dc4d1c992503e48bd5fe66
|
||||
|
||||
PODFILE CHECKSUM: bd8f39f5f1fa7e2c55f59c911d2c5a464617dbd0
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
18
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h
generated
Normal file
18
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import <Expecta/Expecta.h>
|
||||
#import "ExpectaObject+FBSnapshotTest.h"
|
||||
|
||||
@interface EXPExpectFBSnapshotTest : NSObject
|
||||
@end
|
||||
|
||||
/// Set the default folder for image tests to run in
|
||||
extern void setGlobalReferenceImageDir(char *reference);
|
||||
|
||||
EXPMatcherInterface(haveValidSnapshot, (void));
|
||||
EXPMatcherInterface(recordSnapshot, (void));
|
||||
|
||||
EXPMatcherInterface(haveValidSnapshotNamed, (NSString *snapshot));
|
||||
EXPMatcherInterface(recordSnapshotNamed, (NSString *snapshot));
|
||||
|
||||
EXPMatcherInterface(haveValidSnapshotNamedWithTolerance, (NSString *snapshot, CGFloat tolerance));
|
||||
EXPMatcherInterface(haveValidSnapshotWithTolerance, (CGFloat tolerance));
|
||||
311
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.m
generated
Normal file
311
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.m
generated
Normal file
@@ -0,0 +1,311 @@
|
||||
#import "EXPMatchers+FBSnapshotTest.h"
|
||||
#import <Expecta/EXPMatcherHelpers.h>
|
||||
#import <FBSnapshotTestCase/FBSnapshotTestController.h>
|
||||
|
||||
@interface EXPExpectFBSnapshotTest()
|
||||
@property (nonatomic, strong) NSString *referenceImagesDirectory;
|
||||
@end
|
||||
|
||||
@implementation EXPExpectFBSnapshotTest
|
||||
|
||||
+ (id)instance
|
||||
{
|
||||
static EXPExpectFBSnapshotTest *instance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
+ (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer snapshot:(NSString *)snapshot testCase:(id)testCase record:(BOOL)record referenceDirectory:(NSString *)referenceDirectory tolerance:(CGFloat)tolerance error:(NSError **)error
|
||||
|
||||
{
|
||||
FBSnapshotTestController *snapshotController = [[FBSnapshotTestController alloc] initWithTestClass:[testCase class]];
|
||||
snapshotController.recordMode = record;
|
||||
snapshotController.referenceImagesDirectory = referenceDirectory;
|
||||
snapshotController.usesDrawViewHierarchyInRect = [Expecta usesDrawViewHierarchyInRect];
|
||||
snapshotController.deviceAgnostic = [Expecta isDeviceAgnostic];
|
||||
|
||||
if (! snapshotController.referenceImagesDirectory) {
|
||||
[NSException raise:@"Missing value for referenceImagesDirectory" format:@"Call [[EXPExpectFBSnapshotTest instance] setReferenceImagesDirectory"];
|
||||
}
|
||||
|
||||
return [snapshotController compareSnapshotOfViewOrLayer:viewOrLayer
|
||||
selector:NSSelectorFromString(snapshot)
|
||||
identifier:nil
|
||||
tolerance:tolerance
|
||||
error:error];
|
||||
}
|
||||
|
||||
+ (NSString *)combinedError:(NSString *)message test:(NSString *)test error:(NSError *)error
|
||||
{
|
||||
NSAssert(message, @"missing message");
|
||||
NSAssert(test, @"missing test name");
|
||||
|
||||
NSMutableArray *ary = [NSMutableArray array];
|
||||
|
||||
[ary addObject:[NSString stringWithFormat:@"%@ %@", message, test]];
|
||||
|
||||
for(NSString *key in error.userInfo.keyEnumerator) {
|
||||
[ary addObject:[NSString stringWithFormat:@" %@: %@", key, [error.userInfo valueForKey:key]]];
|
||||
}
|
||||
|
||||
return [ary componentsJoinedByString:@"\n"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void setGlobalReferenceImageDir(char *reference) {
|
||||
NSString *referenceImagesDirectory = [NSString stringWithFormat:@"%s", reference];
|
||||
[[EXPExpectFBSnapshotTest instance] setReferenceImagesDirectory:referenceImagesDirectory];
|
||||
};
|
||||
|
||||
@interface EXPExpect(ReferenceDirExtension)
|
||||
- (NSString *)_getDefaultReferenceDirectory;
|
||||
@end
|
||||
|
||||
@implementation EXPExpect(ReferenceDirExtension)
|
||||
|
||||
- (NSString *)_getDefaultReferenceDirectory
|
||||
{
|
||||
NSString *globalReference = [[EXPExpectFBSnapshotTest instance] referenceImagesDirectory];
|
||||
if (globalReference) {
|
||||
return globalReference;
|
||||
}
|
||||
|
||||
// Search the test file's path to find the first folder with the substring "tests"
|
||||
// then append "/ReferenceImages" and use that
|
||||
|
||||
NSString *testFileName = [NSString stringWithCString:self.fileName encoding:NSUTF8StringEncoding];
|
||||
NSArray *pathComponents = [testFileName pathComponents];
|
||||
|
||||
NSString *firstFolderFound = nil;
|
||||
|
||||
for (NSString *folder in pathComponents.reverseObjectEnumerator) {
|
||||
if ([folder.lowercaseString rangeOfString:@"tests"].location != NSNotFound) {
|
||||
NSArray *folderPathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents indexOfObject:folder] + 1)];
|
||||
NSString *referenceImagesPath = [NSString stringWithFormat:@"%@/ReferenceImages", [folderPathComponents componentsJoinedByString:@"/"]];
|
||||
|
||||
if (!firstFolderFound) {
|
||||
firstFolderFound = referenceImagesPath;
|
||||
}
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
BOOL referenceDirExists = [[NSFileManager defaultManager] fileExistsAtPath:referenceImagesPath isDirectory:&isDirectory];
|
||||
|
||||
// if the folder exists, this is the reference dir for sure
|
||||
if (referenceDirExists && isDirectory) {
|
||||
return referenceImagesPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if a reference folder wasn't found, we should create one
|
||||
if (firstFolderFound) {
|
||||
return firstFolderFound;
|
||||
}
|
||||
|
||||
[NSException raise:@"Could not infer reference image folder" format:@"You should provide a reference dir using setGlobalReferenceImageDir(FB_REFERENCE_IMAGE_DIR);"];
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#import <Specta/Specta.h>
|
||||
#import <Specta/SpectaUtility.h>
|
||||
#import <Specta/SPTExample.h>
|
||||
|
||||
NSString *sanitizedTestPath();
|
||||
|
||||
NSString *sanitizedTestPath(){
|
||||
id compiledExample = [[NSThread currentThread] threadDictionary][@"SPTCurrentSpec"]; // SPTSpec
|
||||
NSString *name;
|
||||
if ([compiledExample respondsToSelector:@selector(name)]) {
|
||||
// Specta 0.3 syntax
|
||||
name = [compiledExample performSelector:@selector(name)];
|
||||
} else if ([compiledExample respondsToSelector:@selector(fileName)]) {
|
||||
// Specta 0.2 syntax
|
||||
name = [compiledExample performSelector:@selector(fileName)];
|
||||
}
|
||||
name = [[[[name componentsSeparatedByString:@" test_"] lastObject] stringByReplacingOccurrencesOfString:@"__" withString:@"_"] stringByReplacingOccurrencesOfString:@"]" withString:@""];
|
||||
return name;
|
||||
}
|
||||
|
||||
EXPMatcherImplementationBegin(haveValidSnapshotWithTolerance, (CGFloat tolerance)){
|
||||
__block NSError *error = nil;
|
||||
|
||||
prerequisite(^BOOL{
|
||||
return actual != nil;
|
||||
});
|
||||
|
||||
|
||||
match(^BOOL{
|
||||
NSString *referenceImageDir = [self _getDefaultReferenceDirectory];
|
||||
NSString *name = sanitizedTestPath();
|
||||
if ([actual isKindOfClass:UIViewController.class]) {
|
||||
[actual beginAppearanceTransition:YES animated:NO];
|
||||
[actual endAppearanceTransition];
|
||||
|
||||
actual = [actual view];
|
||||
}
|
||||
|
||||
return [EXPExpectFBSnapshotTest compareSnapshotOfViewOrLayer:actual snapshot:name testCase:[self testCase] record:NO referenceDirectory:referenceImageDir tolerance:tolerance error:&error];
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
if (!actual) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into haveValidSnapshot." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected a matching snapshot in" test:sanitizedTestPath() error:error];
|
||||
});
|
||||
|
||||
failureMessageForNotTo(^NSString *{
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to not have a matching snapshot in" test:sanitizedTestPath() error:error];
|
||||
});
|
||||
}
|
||||
EXPMatcherImplementationEnd
|
||||
|
||||
EXPMatcherImplementationBegin(haveValidSnapshot, (void)) {
|
||||
return self.haveValidSnapshotWithTolerance(0);
|
||||
}
|
||||
EXPMatcherImplementationEnd
|
||||
|
||||
EXPMatcherImplementationBegin(recordSnapshot, (void)) {
|
||||
__block NSError *error = nil;
|
||||
|
||||
BOOL actualIsViewLayerOrViewController = ([actual isKindOfClass:UIView.class] || [actual isKindOfClass:CALayer.class] || [actual isKindOfClass:UIViewController.class]);
|
||||
|
||||
prerequisite(^BOOL{
|
||||
return actual != nil && actualIsViewLayerOrViewController;
|
||||
});
|
||||
|
||||
match(^BOOL{
|
||||
NSString *referenceImageDir = [self _getDefaultReferenceDirectory];
|
||||
// For view controllers do the viewWill/viewDid dance, then pass view through
|
||||
if ([actual isKindOfClass:UIViewController.class]) {
|
||||
|
||||
[actual beginAppearanceTransition:YES animated:NO];
|
||||
[actual endAppearanceTransition];
|
||||
actual = [actual view];
|
||||
}
|
||||
|
||||
[EXPExpectFBSnapshotTest compareSnapshotOfViewOrLayer:actual snapshot:sanitizedTestPath() testCase:[self testCase] record:YES referenceDirectory:referenceImageDir tolerance:0 error:&error];
|
||||
return NO;
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
if (!actual) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into recordSnapshot." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
|
||||
if (!actualIsViewLayerOrViewController) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Expected a View, Layer or View Controller." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
if (error) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to record a snapshot in" test:sanitizedTestPath() error:error];
|
||||
} else {
|
||||
return [NSString stringWithFormat:@"snapshot %@ successfully recorded, replace recordSnapshot with a check", sanitizedTestPath()];
|
||||
}
|
||||
});
|
||||
|
||||
failureMessageForNotTo(^NSString *{
|
||||
if (error) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to record a snapshot in" test:sanitizedTestPath() error:error];
|
||||
} else {
|
||||
return [NSString stringWithFormat:@"snapshot %@ successfully recorded, replace recordSnapshot with a check", sanitizedTestPath()];
|
||||
}
|
||||
});
|
||||
}
|
||||
EXPMatcherImplementationEnd
|
||||
|
||||
EXPMatcherImplementationBegin(haveValidSnapshotNamedWithTolerance, (NSString *snapshot, CGFloat tolerance)) {
|
||||
BOOL snapshotIsNil = (snapshot == nil);
|
||||
__block NSError *error = nil;
|
||||
|
||||
prerequisite(^BOOL{
|
||||
return actual != nil && !(snapshotIsNil);
|
||||
});
|
||||
|
||||
match(^BOOL{
|
||||
NSString *referenceImageDir = [self _getDefaultReferenceDirectory];
|
||||
if ([actual isKindOfClass:UIViewController.class]) {
|
||||
[actual beginAppearanceTransition:YES animated:NO];
|
||||
[actual endAppearanceTransition];
|
||||
|
||||
actual = [actual view];
|
||||
}
|
||||
return [EXPExpectFBSnapshotTest compareSnapshotOfViewOrLayer:actual snapshot:snapshot testCase:[self testCase] record:NO referenceDirectory:referenceImageDir tolerance:tolerance error:&error];
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
if (!actual) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into haveValidSnapshotNamed." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected a matching snapshot named" test:snapshot error:error];
|
||||
|
||||
});
|
||||
|
||||
failureMessageForNotTo(^NSString *{
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected not to have a matching snapshot named" test:snapshot error:error];
|
||||
});
|
||||
}
|
||||
EXPMatcherImplementationEnd
|
||||
|
||||
EXPMatcherImplementationBegin(haveValidSnapshotNamed, (NSString *snapshot)) {
|
||||
return self.haveValidSnapshotNamedWithTolerance(snapshot, 0);
|
||||
}
|
||||
EXPMatcherImplementationEnd
|
||||
|
||||
EXPMatcherImplementationBegin(recordSnapshotNamed, (NSString *snapshot)) {
|
||||
BOOL snapshotExists = (snapshot != nil);
|
||||
BOOL actualIsViewLayerOrViewController = ([actual isKindOfClass:UIView.class] || [actual isKindOfClass:CALayer.class] || [actual isKindOfClass:UIViewController.class]);
|
||||
__block NSError *error = nil;
|
||||
id actualRef = actual;
|
||||
|
||||
prerequisite(^BOOL{
|
||||
return actualRef != nil && snapshotExists && actualIsViewLayerOrViewController;
|
||||
});
|
||||
|
||||
match(^BOOL{
|
||||
NSString *referenceImageDir = [self _getDefaultReferenceDirectory];
|
||||
// For view controllers do the viewWill/viewDid dance, then pass view through
|
||||
if ([actual isKindOfClass:UIViewController.class]) {
|
||||
[actual beginAppearanceTransition:YES animated:NO];
|
||||
[actual endAppearanceTransition];
|
||||
actual = [actual view];
|
||||
}
|
||||
|
||||
[EXPExpectFBSnapshotTest compareSnapshotOfViewOrLayer:actual snapshot:snapshot testCase:[self testCase] record:YES referenceDirectory:referenceImageDir tolerance:0 error:&error];
|
||||
return NO;
|
||||
});
|
||||
|
||||
failureMessageForTo(^NSString *{
|
||||
if (!actual) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into recordSnapshotNamed." test:sanitizedTestPath() error:nil];
|
||||
}
|
||||
if (!actualIsViewLayerOrViewController) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Expected a View, Layer or View Controller." test:snapshot error:nil];
|
||||
}
|
||||
if (error) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to record a matching snapshot named" test:snapshot error:error];
|
||||
} else {
|
||||
return [NSString stringWithFormat:@"snapshot %@ successfully recorded, replace recordSnapshot with a check", snapshot];
|
||||
}
|
||||
});
|
||||
|
||||
failureMessageForNotTo(^NSString *{
|
||||
if (!actualIsViewLayerOrViewController) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"Expected a View, Layer or View Controller." test:snapshot error:nil];
|
||||
}
|
||||
if (error) {
|
||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to record a matching snapshot named" test:snapshot error:error];
|
||||
} else {
|
||||
return [NSString stringWithFormat:@"snapshot %@ successfully recorded, replace recordSnapshot with a check", snapshot];
|
||||
}
|
||||
});
|
||||
}
|
||||
EXPMatcherImplementationEnd
|
||||
21
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/ExpectaObject+FBSnapshotTest.h
generated
Normal file
21
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/ExpectaObject+FBSnapshotTest.h
generated
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// ExpectaObject+FBSnapshotTest.h
|
||||
// Expecta+Snapshots
|
||||
//
|
||||
// Created by John Boiles on 8/3/15.
|
||||
// Copyright (c) 2015 Expecta+Snapshots All rights reserved.
|
||||
//
|
||||
|
||||
#import <Expecta/ExpectaObject.h>
|
||||
|
||||
@interface Expecta (FBSnapshotTest)
|
||||
|
||||
+ (void)setUsesDrawViewHierarchyInRect:(BOOL)usesDrawViewHierarchyInRect;
|
||||
|
||||
+ (BOOL)usesDrawViewHierarchyInRect;
|
||||
|
||||
+ (void)setDeviceAgnostic:(BOOL)deviceAgnostic;
|
||||
|
||||
+ (BOOL)isDeviceAgnostic;
|
||||
|
||||
@end
|
||||
36
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/ExpectaObject+FBSnapshotTest.m
generated
Normal file
36
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/ExpectaObject+FBSnapshotTest.m
generated
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// ExpectaObject+FBSnapshotTest.m
|
||||
// Expecta+Snapshots
|
||||
//
|
||||
// Created by John Boiles on 8/3/15.
|
||||
// Copyright (c) 2015 Expecta+Snapshots All rights reserved.
|
||||
//
|
||||
|
||||
#import "ExpectaObject+FBSnapshotTest.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static NSString const *kUsesDrawViewHierarchyInRectKey = @"ExpectaObject+FBSnapshotTest.usesDrawViewHierarchyInRect";
|
||||
|
||||
@implementation Expecta (FBSnapshotTest)
|
||||
|
||||
+ (void)setUsesDrawViewHierarchyInRect:(BOOL)usesDrawViewHierarchyInRect {
|
||||
objc_setAssociatedObject(self, (__bridge const void *)(kUsesDrawViewHierarchyInRectKey), @(usesDrawViewHierarchyInRect), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
+ (BOOL)usesDrawViewHierarchyInRect {
|
||||
NSNumber *usesDrawViewHierarchyInRect = objc_getAssociatedObject(self, (__bridge const void *)(kUsesDrawViewHierarchyInRectKey));
|
||||
return usesDrawViewHierarchyInRect.boolValue;
|
||||
}
|
||||
|
||||
+ (void)setDeviceAgnostic:(BOOL)deviceAgnostic
|
||||
{
|
||||
objc_setAssociatedObject(self, @selector(isDeviceAgnostic), @(deviceAgnostic), OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
|
||||
+ (BOOL)isDeviceAgnostic
|
||||
{
|
||||
NSNumber *isDeviceAgnostic = objc_getAssociatedObject(self, @selector(isDeviceAgnostic));
|
||||
return isDeviceAgnostic.boolValue;
|
||||
}
|
||||
|
||||
@end
|
||||
22
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/LICENSE.md
generated
Normal file
22
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/LICENSE.md
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2014 Daniel Doubrovkine, Artsy Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
96
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/README.md
generated
Normal file
96
Example/SubModules/FURenderKit/Example/Pods/Expecta+Snapshots/README.md
generated
Normal file
@@ -0,0 +1,96 @@
|
||||
Expecta Matchers for FBSnapshotTestCase
|
||||
=======================================
|
||||
|
||||
[Expecta](https://github.com/specta/expecta) matchers for [ios-snapshot-test-case](https://github.com/facebook/ios-snapshot-test-case).
|
||||
|
||||
[](https://travis-ci.org/dblock/ios-snapshot-test-case-expecta)
|
||||
|
||||
### Usage
|
||||
|
||||
Add `Expecta+Snapshots` to your Podfile, the latest `FBSnapshotTestCase` will come in as a dependency.
|
||||
|
||||
``` ruby
|
||||
pod 'Expecta+Snapshots'
|
||||
```
|
||||
|
||||
### App setup
|
||||
|
||||
Use `expect(view).to.recordSnapshotNamed(@"unique snapshot name")` to record a snapshot and `expect(view).to.haveValidSnapshotNamed(@"unique snapshot name")` to check it.
|
||||
|
||||
If you project was compiled with Specta included, you have two extra methods that use the spec hierarchy to generate the snapshot name for you: `recordSnapshot()` and `haveValidSnapshot()`. You should only call these once per `it()` block.
|
||||
|
||||
If you need the `usesDrawViewHierarchyInRect` property in order to correctly render UIVisualEffect, UIAppearance and Size Classes, call `[Expecta setUsesDrawViewHierarchyInRect:NO];` inside `beforeAll`.
|
||||
|
||||
``` Objective-C
|
||||
#define EXP_SHORTHAND
|
||||
#include <Specta/Specta.h>
|
||||
#include <Expecta/Expecta.h>
|
||||
#include <Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h>
|
||||
#include "FBExampleView.h"
|
||||
|
||||
SpecBegin(FBExampleView)
|
||||
|
||||
describe(@"manual matching", ^{
|
||||
|
||||
it(@"matches view", ^{
|
||||
FBExampleView *view = [[FBExampleView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
|
||||
expect(view).to.recordSnapshotNamed(@"FBExampleView");
|
||||
expect(view).to.haveValidSnapshotNamed(@"FBExampleView");
|
||||
});
|
||||
|
||||
it(@"doesn't match a view", ^{
|
||||
FBExampleView *view = [[FBExampleView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
|
||||
expect(view).toNot.haveValidSnapshotNamed(@"FBExampleViewDoesNotExist");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe(@"test name derived matching", ^{
|
||||
|
||||
it(@"matches view", ^{
|
||||
FBExampleView *view = [[FBExampleView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
|
||||
expect(view).to.recordSnapshot();
|
||||
expect(view).to.haveValidSnapshot();
|
||||
});
|
||||
|
||||
it(@"doesn't match a view", ^{
|
||||
FBExampleView *view = [[FBExampleView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
|
||||
expect(view).toNot.haveValidSnapshot();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
SpecEnd
|
||||
```
|
||||
|
||||
### Approximation support
|
||||
|
||||
If for some reason you want to specify a tolerance for your test, you can use either named or unnamed matchers, where the `tolerance` parameter is a `CGFloat` in the interval `[0, 1]` and it represents the minimum ratio of unmatched points by the total number of points in your snapshot. In the example below, a tolerance of `0.01` means our `view` could be up to `1%` different from the reference image.
|
||||
|
||||
``` Objective-C
|
||||
expect(view).to.haveValidSnapshotWithTolerance(0.01);
|
||||
expect(view).to.haveValidSnapshotNamedWithTolerance(@"unique snapshot name", 0.01);
|
||||
```
|
||||
|
||||
### Sane defaults
|
||||
|
||||
`EXPMatchers+FBSnapshotTest` will automatically figure out the tests folder, and [add a reference image](https://github.com/dblock/ios-snapshot-test-case-expecta/blob/master/EXPMatchers%2BFBSnapshotTest.m#L84-L85) directory, if you'd like to override this, you should include a `beforeAll` block setting the `setGlobalReferenceImageDir` in each file containing tests.
|
||||
|
||||
```
|
||||
beforeAll(^{
|
||||
setGlobalReferenceImageDir(FB_REFERENCE_IMAGE_DIR);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
A complete project can be found in [FBSnapshotTestCaseDemo](FBSnapshotTestCaseDemo).
|
||||
|
||||
Notably, take a look at [FBSnapshotTestCaseDemoSpecs.m](FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/FBSnapshotTestCaseDemoSpecs.m) for a complete example, which is an expanded Specta version version of [FBSnapshotTestCaseDemoTests.m](https://github.com/facebook/ios-snapshot-test-case/blob/master/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/FBSnapshotTestCaseDemoTests.m).
|
||||
|
||||
Finally you can consult the tests for [ARTiledImageView](https://github.com/dblock/ARTiledImageView/tree/master/IntegrationTests) or [NAMapKit](https://github.com/neilang/NAMapKit/tree/master/Demo/DemoTests).
|
||||
|
||||
### License
|
||||
|
||||
MIT, see [LICENSE](LICENSE.md)
|
||||
25
Example/SubModules/FURenderKit/Example/Pods/Expecta/Expecta/EXPBlockDefinedMatcher.h
generated
Normal file
25
Example/SubModules/FURenderKit/Example/Pods/Expecta/Expecta/EXPBlockDefinedMatcher.h
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// EXPRuntimeMatcher.h
|
||||
// Expecta
|
||||
//
|
||||
// Created by Luke Redpath on 26/03/2012.
|
||||
// Copyright (c) 2012 Peter Jihoon Kim. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "EXPMatcher.h"
|
||||
#import "EXPDefines.h"
|
||||
|
||||
@interface EXPBlockDefinedMatcher : NSObject <EXPMatcher> {
|
||||
EXPBoolBlock prerequisiteBlock;
|
||||
EXPBoolBlock matchBlock;
|
||||
EXPStringBlock failureMessageForToBlock;
|
||||
EXPStringBlock failureMessageForNotToBlock;
|
||||
}
|
||||
|
||||
@property(nonatomic, copy) EXPBoolBlock prerequisiteBlock;
|
||||
@property(nonatomic, copy) EXPBoolBlock matchBlock;
|
||||
@property(nonatomic, copy) EXPStringBlock failureMessageForToBlock;
|
||||
@property(nonatomic, copy) EXPStringBlock failureMessageForNotToBlock;
|
||||
|
||||
@end
|
||||
60
Example/SubModules/FURenderKit/Example/Pods/Expecta/Expecta/EXPBlockDefinedMatcher.m
generated
Normal file
60
Example/SubModules/FURenderKit/Example/Pods/Expecta/Expecta/EXPBlockDefinedMatcher.m
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// EXPRuntimeMatcher.m
|
||||
// Expecta
|
||||
//
|
||||
// Created by Luke Redpath on 26/03/2012.
|
||||
// Copyright (c) 2012 Peter Jihoon Kim. All rights reserved.
|
||||
//
|
||||
|
||||
#import "EXPBlockDefinedMatcher.h"
|
||||
|
||||
@implementation EXPBlockDefinedMatcher
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
self.prerequisiteBlock = nil;
|
||||
self.matchBlock = nil;
|
||||
self.failureMessageForToBlock = nil;
|
||||
self.failureMessageForNotToBlock = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@synthesize prerequisiteBlock;
|
||||
@synthesize matchBlock;
|
||||
@synthesize failureMessageForToBlock;
|
||||
@synthesize failureMessageForNotToBlock;
|
||||
|
||||
- (BOOL)meetsPrerequesiteFor:(id)actual
|
||||
{
|
||||
if (self.prerequisiteBlock) {
|
||||
return self.prerequisiteBlock();
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)matches:(id)actual
|
||||
{
|
||||
if (self.matchBlock) {
|
||||
return self.matchBlock();
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)failureMessageForTo:(id)actual
|
||||
{
|
||||
if (self.failureMessageForToBlock) {
|
||||
return self.failureMessageForToBlock();
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)failureMessageForNotTo:(id)actual
|
||||
{
|
||||
if (self.failureMessageForNotToBlock) {
|
||||
return self.failureMessageForNotToBlock();
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
17
Example/SubModules/FURenderKit/Example/Pods/Expecta/Expecta/EXPDefines.h
generated
Normal file
17
Example/SubModules/FURenderKit/Example/Pods/Expecta/Expecta/EXPDefines.h
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// EXPDefines.h
|
||||
// Expecta
|
||||
//
|
||||
// Created by Luke Redpath on 26/03/2012.
|
||||
// Copyright (c) 2012 Peter Jihoon Kim. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Expecta_EXPDefines_h
|
||||
#define Expecta_EXPDefines_h
|
||||
|
||||
typedef void (^EXPBasicBlock)(void);
|
||||
typedef id (^EXPIdBlock)(void);
|
||||
typedef BOOL (^EXPBoolBlock)(void);
|
||||
typedef NSString *(^EXPStringBlock)(void);
|
||||
|
||||
#endif
|
||||
13
Example/SubModules/FURenderKit/Example/Pods/Expecta/Expecta/EXPDoubleTuple.h
generated
Normal file
13
Example/SubModules/FURenderKit/Example/Pods/Expecta/Expecta/EXPDoubleTuple.h
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface EXPDoubleTuple : NSObject {
|
||||
double *_values;
|
||||
size_t _size;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) double *values;
|
||||
@property (nonatomic, assign) size_t size;
|
||||
|
||||
- (instancetype)initWithDoubleValues:(double *)values size:(size_t)size NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user