├── .github
└── FUNDING.yml
├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── .travis.yml
├── Example
├── Podfile
├── TTGTagCollectionView.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── TTGTagCollectionView_Example.xcscheme
│ │ └── TTGTagCollectionView_Tests.xcscheme
├── TTGTagCollectionView.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── TTGTagCollectionView
│ ├── Images.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-60@2x.png
│ │ │ ├── Icon-60@3x.png
│ │ │ ├── Icon-76.png
│ │ │ ├── Icon-76@2x.png
│ │ │ ├── Icon-83.5@2x.png
│ │ │ ├── Icon-Notification.png
│ │ │ ├── Icon-Notification@2x.png
│ │ │ ├── Icon-Notification@3x.png
│ │ │ ├── Icon-Small-40.png
│ │ │ ├── Icon-Small-40@2x.png
│ │ │ ├── Icon-Small-40@3x.png
│ │ │ ├── Icon-Small.png
│ │ │ ├── Icon-Small@2x.png
│ │ │ └── Icon-Small@3x.png
│ │ ├── Contents.json
│ │ ├── bluefaces_1.imageset
│ │ │ ├── Contents.json
│ │ │ └── bluefaces_1.png
│ │ ├── bluefaces_2.imageset
│ │ │ ├── Contents.json
│ │ │ └── bluefaces_2.png
│ │ ├── bluefaces_3.imageset
│ │ │ ├── Contents.json
│ │ │ └── bluefaces_3.png
│ │ ├── bluefaces_4.imageset
│ │ │ ├── Contents.json
│ │ │ └── bluefaces_4.png
│ │ └── logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── Icon-60@2x.png
│ ├── Launch Screen.storyboard
│ ├── Main.storyboard
│ ├── TTGAppDelegate.h
│ ├── TTGAppDelegate.m
│ ├── TTGExample1ViewController.h
│ ├── TTGExample1ViewController.m
│ ├── TTGExample2ViewController.h
│ ├── TTGExample2ViewController.m
│ ├── TTGExample3ViewController.h
│ ├── TTGExample3ViewController.m
│ ├── TTGExample4TableViewCell.h
│ ├── TTGExample4TableViewCell.m
│ ├── TTGExample4ViewController.h
│ ├── TTGExample4ViewController.m
│ ├── TTGExample5ViewController.h
│ ├── TTGExample5ViewController.m
│ ├── TTGExample6ViewController.h
│ ├── TTGExample6ViewController.m
│ ├── TTGExample7ViewController.h
│ ├── TTGExample7ViewController.m
│ ├── TTGExample8ViewController.h
│ ├── TTGExample8ViewController.m
│ ├── TTGExample9ViewController.h
│ ├── TTGExample9ViewController.m
│ ├── TTGTagCollectionView-Info.plist
│ ├── TTGTagCollectionView-Prefix.pch
│ ├── en.lproj
│ │ └── InfoPlist.strings
│ └── main.m
└── Tests
│ ├── Tests-Info.plist
│ ├── Tests-Prefix.pch
│ ├── Tests.m
│ └── en.lproj
│ └── InfoPlist.strings
├── ExampleSwift
├── Podfile
├── TTGTagSwiftExample.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── TTGTagSwiftExample.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── TTGTagSwiftExample
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ ├── SceneDelegate.swift
│ └── ViewController.swift
├── LICENSE
├── Package.swift
├── README.md
├── Resources
├── alignment_type.png
├── code_structure.png
├── demo_example.jpeg
└── screen_shot.png
├── Sources
├── TTGTagCollectionView-Bridging-Header.h
├── TTGTagCollectionView.h
├── TTGTagCollectionView.m
├── TTGTextTag.h
├── TTGTextTag.m
├── TTGTextTagAttributedStringContent.h
├── TTGTextTagAttributedStringContent.m
├── TTGTextTagCollectionView.h
├── TTGTextTagCollectionView.m
├── TTGTextTagContent.h
├── TTGTextTagContent.m
├── TTGTextTagStringContent.h
├── TTGTextTagStringContent.m
├── TTGTextTagStyle.h
└── TTGTextTagStyle.m
├── TTGTagCollectionView.podspec
└── TTGTagCollectionView
├── TTGTagCollectionView.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
└── TTGTagCollectionView
└── Info.plist
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [zekunyan]
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Mac OS X
2 | .DS_Store
3 |
4 | # Xcode
5 |
6 | ## Build generated
7 | build/
8 | DerivedData
9 |
10 | ## Various settings
11 | *.pbxuser
12 | !default.pbxuser
13 | *.mode1v3
14 | !default.mode1v3
15 | *.mode2v3
16 | !default.mode2v3
17 | *.perspectivev3
18 | !default.perspectivev3
19 | xcuserdata
20 |
21 | ## Other
22 | *.xccheckout
23 | *.moved-aside
24 | *.xcuserstate
25 | *.xcscmblueprint
26 |
27 | ## Obj-C/Swift specific
28 | *.hmap
29 | *.ipa
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | .build/
37 |
38 | # Carthage
39 | Carthage/Build
40 |
41 | # AppCode
42 | .idea/
43 |
44 | # CocoaPods
45 | Pods/
46 | Podfile.lock
47 | TaobaoEnv
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | osx_image: xcode12.4
2 | language: objective-c
3 | script:
4 | - set -o pipefail
5 | - xcodebuild -version
6 | - xcodebuild -showsdks
7 | - xcodebuild clean build -project TTGTagCollectionView/TTGTagCollectionView.xcodeproj -alltargets ONLY_ACTIVE_ARCH=NO CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO PROVISIONING_PROFILE_SPECIFIER="" PROVISIONING_PROFILE="" CODE_SIGNING_ALLOWED=NO | xcpretty
8 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 |
3 | use_frameworks!
4 |
5 | platform :ios, '11.0'
6 |
7 | target 'TTGTagCollectionView_Example' do
8 | pod 'TTGTagCollectionView', :path => '../'
9 | pod 'Masonry', :git => 'git@github.com:SnapKit/Masonry.git', :tag => 'v1.1.0'
10 | pod 'SVPullToRefresh', :git => 'git@github.com:samvermette/SVPullToRefresh.git', :tag => '0.4.1'
11 |
12 | target 'TTGTagCollectionView_Tests' do
13 | inherit! :search_paths
14 | end
15 | end
16 |
17 | post_install do |installer|
18 | installer.generated_projects.each do |project|
19 | project.targets.each do |target|
20 | target.build_configurations.each do |config|
21 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView.xcodeproj/xcshareddata/xcschemes/TTGTagCollectionView_Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView.xcodeproj/xcshareddata/xcschemes/TTGTagCollectionView_Tests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
39 |
40 |
41 |
42 |
48 |
49 |
51 |
52 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-Notification@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-Notification@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-Small@2x.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-Small@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-Small-40@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-Small-40@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-60@2x.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-60@3x.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "20x20",
53 | "idiom" : "ipad",
54 | "filename" : "Icon-Notification.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-Notification@2x.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "29x29",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-Small.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-Small@2x.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "40x40",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-Small-40.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-Small-40@2x.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-76.png",
91 | "scale" : "1x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-76@2x.png",
97 | "scale" : "2x"
98 | },
99 | {
100 | "size" : "83.5x83.5",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-83.5@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "idiom" : "ios-marketing",
107 | "size" : "1024x1024",
108 | "scale" : "1x"
109 | }
110 | ],
111 | "info" : {
112 | "version" : 1,
113 | "author" : "xcode"
114 | }
115 | }
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Notification.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Notification@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Notification@2x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Notification@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Notification@3x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small-40.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/bluefaces_1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "bluefaces_1.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/bluefaces_1.imageset/bluefaces_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/bluefaces_1.imageset/bluefaces_1.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/bluefaces_2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "bluefaces_2.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/bluefaces_2.imageset/bluefaces_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/bluefaces_2.imageset/bluefaces_2.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/bluefaces_3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "bluefaces_3.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/bluefaces_3.imageset/bluefaces_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/bluefaces_3.imageset/bluefaces_3.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/bluefaces_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "bluefaces_4.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/bluefaces_4.imageset/bluefaces_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/bluefaces_4.imageset/bluefaces_4.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "Icon-60@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Images.xcassets/logo.imageset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Example/TTGTagCollectionView/Images.xcassets/logo.imageset/Icon-60@2x.png
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/Launch Screen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGAppDelegate.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 12/11/2015.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | @interface TTGAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGAppDelegate.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 12/11/2015.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGAppDelegate.h"
10 |
11 | @implementation TTGAppDelegate
12 |
13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
14 | return YES;
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample1ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample1ViewController.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 15/12/29.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TTGExample1ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample1ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample1ViewController.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 15/12/29.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "TTGExample1ViewController.h"
11 |
12 | @interface TTGExample1ViewController ()
13 | @property (weak, nonatomic) IBOutlet TTGTextTagCollectionView *textTagCollectionView1;
14 | @property (weak, nonatomic) IBOutlet TTGTextTagCollectionView *textTagCollectionView2;
15 | @property (weak, nonatomic) IBOutlet UILabel *logLabel;
16 |
17 | @property (strong, nonatomic) NSArray *tags;
18 | @end
19 |
20 | @implementation TTGExample1ViewController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 |
25 | // Remember to set this to NO
26 | self.automaticallyAdjustsScrollViewInsets = NO;
27 |
28 | // Init Tags
29 | _tags = @[
30 | @"AutoLayoutAutoLayoutAutoLayoutAutoLayoutAutoLayoutAutoLayoutAutoLayoutAutoLayoutAutoLayout",
31 | @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
32 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
33 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
34 | @"For", @"example", @"you", @"can", @"constrain", @"a", @"button",
35 | @"so", @"that", @"it", @"is", @"horizontally", @"centered", @"with",
36 | @"an", @"Image", @"view", @"and", @"so", @"that", @"the", @"button’s",
37 | @"top", @"edge", @"always", @"remains", @"8", @"points", @"below", @"the",
38 | @"image’s", @"bottom", @"If", @"the", @"image", @"view’s", @"size", @"or",
39 | @"position", @"changes", @"the", @"button’s", @"position", @"automatically", @"adjusts", @"to", @"match"
40 | ];
41 |
42 | _logLabel.adjustsFontSizeToFitWidth = YES;
43 | _textTagCollectionView1.delegate = self;
44 | _textTagCollectionView2.delegate = self;
45 |
46 | _textTagCollectionView1.showsVerticalScrollIndicator = NO;
47 | _textTagCollectionView2.showsVerticalScrollIndicator = NO;
48 |
49 | _textTagCollectionView1.horizontalSpacing = 6.0;
50 | _textTagCollectionView1.verticalSpacing = 8.0;
51 |
52 | _textTagCollectionView2.horizontalSpacing = 8;
53 | _textTagCollectionView2.verticalSpacing = 8;
54 |
55 | // Change alignment
56 | _textTagCollectionView1.alignment = TTGTagCollectionAlignmentFillByExpandingWidth;
57 | _textTagCollectionView2.alignment = TTGTagCollectionAlignmentFillByExpandingWidthExceptLastLine;
58 |
59 | // Style1
60 | TTGTextTagStringContent *content = [TTGTextTagStringContent new];
61 | TTGTextTagStringContent *selectedContent = [TTGTextTagStringContent new];
62 | TTGTextTagStyle *style = [TTGTextTagStyle new];
63 | TTGTextTagStyle *selectedStyle = [TTGTextTagStyle new];
64 |
65 | content.textFont = [UIFont boldSystemFontOfSize:18.0f];
66 | selectedContent.textFont = content.textFont;
67 |
68 | content.textColor = [UIColor colorWithRed:0.23 green:0.23 blue:0.23 alpha:1.00];
69 | selectedContent.textColor = [UIColor whiteColor];
70 |
71 | style.backgroundColor = [UIColor colorWithRed:0.31 green:0.70 blue:0.80 alpha:1.00];
72 | selectedStyle.backgroundColor = [UIColor colorWithRed:0.38 green:0.36 blue:0.63 alpha:1.00];
73 |
74 | style.borderColor = [UIColor colorWithRed:0.18 green:0.19 blue:0.22 alpha:1.00];
75 | style.borderWidth = 1;
76 |
77 | selectedStyle.borderColor = [UIColor colorWithRed:0.18 green:0.19 blue:0.22 alpha:1.00];
78 | selectedStyle.borderWidth = 1;
79 |
80 | style.shadowColor = [UIColor grayColor];
81 | style.shadowOffset = CGSizeMake(0, 1);
82 | style.shadowOpacity = 0.5f;
83 | style.shadowRadius = 2;
84 |
85 | selectedStyle.shadowColor = [UIColor greenColor];
86 | selectedStyle.shadowOffset = CGSizeMake(0, 2);
87 | selectedStyle.shadowOpacity = 0.5f;
88 | selectedStyle.shadowRadius = 1;
89 |
90 | style.cornerRadius = 2;
91 | selectedStyle.cornerRadius = 4;
92 |
93 | style.extraSpace = CGSizeMake(4, 4);
94 | selectedStyle.extraSpace = style.extraSpace;
95 |
96 | NSMutableArray *tags = [NSMutableArray new];
97 | for (NSString *string in _tags) {
98 | TTGTextTagStringContent *stringContent = [content copy];
99 | stringContent.text = string;
100 | TTGTextTagStringContent *selectedStringContent = [selectedContent copy];
101 | selectedStringContent.text = string;
102 | TTGTextTag *tag = [TTGTextTag new];
103 | tag.content = stringContent;
104 | tag.selectedContent = selectedStringContent;
105 | tag.style = style;
106 | tag.selectedStyle = selectedStyle;
107 | [tags addObject:tag.copy];
108 | }
109 | [_textTagCollectionView1 addTags:tags];
110 |
111 | // Style2
112 | content.textFont = [UIFont systemFontOfSize:18.0f];
113 | selectedContent.textFont = [UIFont systemFontOfSize:20.0f];
114 |
115 | content.textColor = [UIColor whiteColor];
116 | selectedContent.textColor = [UIColor greenColor];
117 |
118 | style.extraSpace = CGSizeMake(12, 12);
119 | selectedStyle.extraSpace = CGSizeMake(12, 12);
120 |
121 | style.backgroundColor = [UIColor colorWithRed:0.10 green:0.53 blue:0.85 alpha:1.00];
122 | selectedStyle.backgroundColor = [UIColor colorWithRed:0.21 green:0.29 blue:0.36 alpha:1.00];
123 |
124 | style.cornerRadius = 12.0f;
125 | style.cornerBottomRight = true;
126 | style.cornerBottomLeft = false;
127 | style.cornerTopRight = false;
128 | style.cornerTopLeft = true;
129 |
130 | selectedStyle.cornerRadius = 8.0f;
131 | selectedStyle.cornerBottomRight = true;
132 | selectedStyle.cornerBottomLeft = false;
133 | selectedStyle.cornerTopRight = true;
134 | selectedStyle.cornerTopLeft = false;
135 |
136 | style.borderWidth = 1;
137 | selectedStyle.borderWidth = 4;
138 |
139 | style.borderColor = [UIColor redColor];
140 | selectedStyle.borderColor = [UIColor orangeColor];
141 |
142 | style.shadowColor = [UIColor blackColor];
143 | style.shadowOffset = CGSizeMake(0, 4);
144 | style.shadowOpacity = 0.3f;
145 | style.shadowRadius = 4;
146 |
147 | selectedStyle.shadowColor = [UIColor redColor];
148 | selectedStyle.shadowOffset = CGSizeMake(0, 1);
149 | selectedStyle.shadowOpacity = 0.3f;
150 | selectedStyle.shadowRadius = 2;
151 |
152 | tags = [NSMutableArray new];
153 | for (NSString *string in _tags) {
154 | TTGTextTagStringContent *stringContent = [content copy];
155 | stringContent.text = string;
156 | TTGTextTagStringContent *selectedStringContent = [selectedContent copy];
157 | selectedStringContent.text = [string stringByAppendingString:@"!"];
158 | TTGTextTag *tag = [TTGTextTag new];
159 | tag.content = stringContent;
160 | tag.selectedContent = selectedStringContent;
161 | tag.style = style;
162 | tag.selectedStyle = selectedStyle;
163 | [tags addObject:tag.copy];
164 | }
165 | [_textTagCollectionView2 addTags:tags];
166 |
167 | // Init selection
168 | [_textTagCollectionView1 updateTagAtIndex:0 selected:YES];
169 | [_textTagCollectionView1 updateTagAtIndex:4 selected:YES];
170 | [_textTagCollectionView1 updateTagAtIndex:6 selected:YES];
171 | [_textTagCollectionView1 updateTagAtIndex:17 selected:YES];
172 |
173 | [_textTagCollectionView2 updateTagAtIndex:0 selected:YES];
174 | [_textTagCollectionView2 updateTagAtIndex:4 selected:YES];
175 | [_textTagCollectionView2 updateTagAtIndex:6 selected:YES];
176 | [_textTagCollectionView2 updateTagAtIndex:17 selected:YES];
177 |
178 | // Load data
179 | [_textTagCollectionView1 reload];
180 | [_textTagCollectionView2 reload];
181 | }
182 |
183 | #pragma mark - TTGTextTagCollectionViewDelegate
184 |
185 | - (void)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView didTapTag:(TTGTextTag *)tag atIndex:(NSUInteger)index {
186 | _logLabel.text = [NSString stringWithFormat:@"Tap tag: %@, at: %ld, selected: %d", tag.content.getContentAttributedString.string, (long) index, tag.selected];
187 | }
188 |
189 | - (void)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView updateContentSize:(CGSize)contentSize {
190 | NSLog(@"text tag collection: %@ new content size: %@", textTagCollectionView, NSStringFromCGSize(contentSize));
191 | }
192 |
193 | @end
194 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample2ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample2ViewController.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 15/12/29.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TTGExample2ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample2ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample2ViewController.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 15/12/29.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "TTGExample2ViewController.h"
11 |
12 | @interface TTGExample2ViewController ()
13 | @property (weak, nonatomic) IBOutlet TTGTagCollectionView *tagCollectionView;
14 | @property (weak, nonatomic) IBOutlet UILabel *logLabel;
15 |
16 | @property (strong, nonatomic) NSMutableArray *tagViews;
17 | @end
18 |
19 | @implementation TTGExample2ViewController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 |
24 | _tagCollectionView.delegate = self;
25 | _tagCollectionView.dataSource = self;
26 | _logLabel.adjustsFontSizeToFitWidth = YES;
27 | _tagViews = [NSMutableArray new];
28 |
29 | UIColor *backgroundColor1 = [UIColor colorWithRed:0.30 green:0.72 blue:0.53 alpha:1.00];
30 | UIColor *backgroundColor2 = [UIColor colorWithRed:0.10 green:0.53 blue:0.85 alpha:1.00];
31 | UIColor *backgroundColor3 = [UIColor colorWithRed:0.97 green:0.64 blue:0.27 alpha:1.00];
32 |
33 | [_tagViews addObject:[self newLabelWithText:@"AutoLayout" fontSize:14.0f textColor:[UIColor whiteColor] backgroundColor:backgroundColor1]];
34 | [_tagViews addObject:[self newButtonWithTitle:@"Button1" fontSize:18.0f backgroundColor:backgroundColor2]];
35 | [_tagViews addObject:[self newImageViewWithImage:[UIImage imageNamed:@"bluefaces_1"]]];
36 | [_tagViews addObject:[self newLabelWithText:@"dynamically" fontSize:20.0f textColor:[UIColor whiteColor] backgroundColor:backgroundColor1]];
37 | [_tagViews addObject:[self newButtonWithTitle:@"Button2" fontSize:16.0f backgroundColor:backgroundColor3]];
38 | [_tagViews addObject:[self newButtonWithTitle:@"Button3" fontSize:15.0f backgroundColor:backgroundColor2]];
39 | [_tagViews addObject:[self newImageViewWithImage:[UIImage imageNamed:@"bluefaces_2"]]];
40 | [_tagViews addObject:[self newLabelWithText:@"the" fontSize:16.0f textColor:[UIColor blackColor] backgroundColor:backgroundColor1]];
41 | [_tagViews addObject:[self newButtonWithTitle:@"Button4" fontSize:22.0f backgroundColor:backgroundColor2]];
42 | [_tagViews addObject:[self newImageViewWithImage:[UIImage imageNamed:@"bluefaces_3"]]];
43 | [_tagViews addObject:[self newLabelWithText:@"views" fontSize:12.0f
44 | textColor:[UIColor colorWithRed:0.21 green:0.29 blue:0.36 alpha:1.00]
45 | backgroundColor:backgroundColor3]];
46 | [_tagViews addObject:[self newButtonWithTitle:@"Button5" fontSize:15.0f backgroundColor:backgroundColor1]];
47 | [_tagViews addObject:[self newImageViewWithImage:[UIImage imageNamed:@"bluefaces_4"]]];
48 | [_tagViews addObject:[self newImageViewWithImage:[UIImage imageNamed:@"bluefaces_4"]]];
49 |
50 | [_tagCollectionView reload];
51 | }
52 |
53 | #pragma mark - TTGTagCollectionViewDelegate
54 |
55 | - (CGSize)tagCollectionView:(TTGTagCollectionView *)tagCollectionView sizeForTagAtIndex:(NSUInteger)index {
56 | return _tagViews[index].frame.size;
57 | }
58 |
59 | - (void)tagCollectionView:(TTGTagCollectionView *)tagCollectionView didSelectTag:(UIView *)tagView atIndex:(NSUInteger)index {
60 | _logLabel.text = [NSString stringWithFormat:@"Tap tag: %@, at: %ld", tagView.class, (long) index];
61 | }
62 |
63 | #pragma mark - TTGTagCollectionViewDataSource
64 |
65 | - (NSUInteger)numberOfTagsInTagCollectionView:(TTGTagCollectionView *)tagCollectionView {
66 | return _tagViews.count;
67 | }
68 |
69 | - (UIView *)tagCollectionView:(TTGTagCollectionView *)tagCollectionView tagViewForIndex:(NSUInteger)index {
70 | return _tagViews[index];
71 | }
72 |
73 | #pragma mark - Private methods
74 |
75 | - (UILabel *)newLabelWithText:(NSString *)text fontSize:(CGFloat)fontSize textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroudColor {
76 | UILabel *label = [UILabel new];
77 |
78 | label.font = [UIFont systemFontOfSize:fontSize];
79 | label.textAlignment = NSTextAlignmentCenter;
80 | label.text = text;
81 | label.textColor = textColor;
82 | label.backgroundColor = backgroudColor;
83 | [label sizeToFit];
84 | label.layer.masksToBounds = YES;
85 | label.layer.cornerRadius = 4.0f;
86 |
87 | [self expandSizeForView:label extraWidth:12 extraHeight:8];
88 |
89 | return label;
90 | }
91 |
92 | - (UIButton *)newButtonWithTitle:(NSString *)title fontSize:(CGFloat)fontSize backgroundColor:(UIColor *)backgroudColor {
93 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
94 |
95 | button.titleLabel.font = [UIFont systemFontOfSize:fontSize];
96 | [button setTitle:title forState:UIControlStateNormal];
97 | button.backgroundColor = backgroudColor;
98 | [button sizeToFit];
99 | button.layer.masksToBounds = YES;
100 | button.layer.cornerRadius = 4.0f;
101 |
102 | [self expandSizeForView:button extraWidth:12 extraHeight:8];
103 |
104 | [button addTarget:self action:@selector(onTap:) forControlEvents:UIControlEventTouchUpInside];
105 |
106 | return button;
107 | }
108 |
109 | - (UIImageView *)newImageViewWithImage:(UIImage *)image {
110 | UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
111 | [imageView sizeToFit];
112 | return imageView;
113 | }
114 |
115 | - (void)expandSizeForView:(UIView *)view extraWidth:(CGFloat)extraWidth extraHeight:(CGFloat)extraHeight {
116 | CGRect frame = view.frame;
117 | frame.size.width += extraWidth;
118 | frame.size.height += extraHeight;
119 | view.frame = frame;
120 | }
121 |
122 | #pragma mark - Action
123 |
124 | - (void)onTap:(UIButton *)button {
125 | _logLabel.text = @"Tap tag button !";
126 | }
127 |
128 | @end
129 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample3ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample3ViewController.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2016/9/29.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TTGExample3ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample3ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample3ViewController.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2016/9/29.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGExample3ViewController.h"
10 | #import
11 |
12 | @interface TTGExample3ViewController ()
13 | @property (nonatomic, strong) TTGTextTagCollectionView *tagView;
14 | @end
15 |
16 | @implementation TTGExample3ViewController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 |
21 | NSArray *tags = @[@"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
22 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
23 | @"on", @"constraints", @"placed", @"on", @"those", @"views"];
24 |
25 | _tagView = [TTGTextTagCollectionView new];
26 | _tagView.alignment = TTGTagCollectionAlignmentFillByExpandingWidth;
27 | _tagView.layer.borderColor = [UIColor grayColor].CGColor;
28 | _tagView.layer.borderWidth = 1;
29 | _tagView.translatesAutoresizingMaskIntoConstraints = NO;
30 | _tagView.onTapBlankArea = ^(CGPoint location) {
31 | NSLog(@"Blank: %@", NSStringFromCGPoint(location));
32 | };
33 | _tagView.onTapAllArea = ^(CGPoint location) {
34 | NSLog(@"All: %@", NSStringFromCGPoint(location));
35 | };
36 | [self.view addSubview:_tagView];
37 |
38 | NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[tagView]-20-|"
39 | options:(NSLayoutFormatOptions) 0 metrics:nil
40 | views:@{@"tagView": _tagView}];
41 | NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:_tagView
42 | attribute:NSLayoutAttributeTop
43 | relatedBy:NSLayoutRelationEqual
44 | toItem:self.view
45 | attribute:NSLayoutAttributeTop
46 | multiplier:1 constant:180];
47 | [self.view addConstraint:topConstraint];
48 | [self.view addConstraints:hConstraints];
49 |
50 | NSMutableArray *textTags = [NSMutableArray new];
51 | for (NSString *string in tags) {
52 | TTGTextTag *textTag = [TTGTextTag tagWithContent:[TTGTextTagStringContent contentWithText:string] style:[TTGTextTagStyle new]];
53 | textTag.selectedStyle.backgroundColor = [UIColor greenColor];
54 | [textTags addObject:textTag];
55 | }
56 | [_tagView addTags:textTags];
57 |
58 | for (NSInteger i = 0; i < 5; i++) {
59 | [_tagView updateTagAtIndex:arc4random_uniform((uint32_t)tags.count) selected:YES];
60 | }
61 |
62 | _tagView.onTapAllArea = ^(CGPoint location) {
63 | NSLog(@"onTapAllArea: %@", NSStringFromCGPoint(location));
64 | };
65 | _tagView.onTapBlankArea = ^(CGPoint location) {
66 | NSLog(@"onTapBlankArea: %@", NSStringFromCGPoint(location));
67 | };
68 |
69 | [_tagView reload];
70 | }
71 |
72 | @end
73 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample4TableViewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample4TableViewCell.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2016/10/1.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class TTGTextTagCollectionView;
12 |
13 | @interface TTGExample4TableViewCell : UITableViewCell
14 | @property (weak, nonatomic) IBOutlet TTGTextTagCollectionView *tagView;
15 | @property (weak, nonatomic) IBOutlet UILabel *label;
16 |
17 | - (void)setTags:(NSArray *)tags;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample4TableViewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample4TableViewCell.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2016/10/1.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGExample4TableViewCell.h"
10 | #import
11 |
12 | @interface TTGExample4TableViewCell ()
13 | @end
14 |
15 | @implementation TTGExample4TableViewCell
16 |
17 | - (void)awakeFromNib {
18 | [super awakeFromNib];
19 |
20 | // Alignment
21 | _tagView.alignment = TTGTagCollectionAlignmentFillByExpandingWidth;
22 |
23 | // Use manual calculate height
24 | _tagView.manualCalculateHeight = YES;
25 | }
26 |
27 | - (void)setTags:(NSArray *)tags {
28 | [_tagView removeAllTags];
29 |
30 | NSMutableArray *textTags = [NSMutableArray new];
31 | for (NSString *string in tags) {
32 | TTGTextTag *textTag = [TTGTextTag tagWithContent:[TTGTextTagStringContent contentWithText:string] style:[TTGTextTagStyle new]];
33 | textTag.selectedStyle.backgroundColor = [UIColor greenColor];
34 | [textTags addObject:textTag];
35 | }
36 | [_tagView addTags:textTags];
37 |
38 | // Use manual height, update preferredMaxLayoutWidth
39 | _tagView.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 16;
40 |
41 | // Random selected
42 | for (NSInteger i = 0; i < 3; i++) {
43 | [_tagView updateTagAtIndex:arc4random_uniform((uint32_t)tags.count) selected:YES];
44 | }
45 | [_tagView reload];
46 | }
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample4ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample4ViewController.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2016/10/1.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TTGExample4ViewController : UITableViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample4ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample4ViewController.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2016/10/1.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGExample4ViewController.h"
10 | #import "TTGExample4TableViewCell.h"
11 |
12 | @interface TTGExample4ViewController ()
13 | @property (nonatomic, strong) NSArray *allTags;
14 | @property (nonatomic, strong) NSMutableArray *cellInfos;
15 | @end
16 |
17 | @implementation TTGExample4ViewController
18 |
19 | - (void)viewDidLoad {
20 | [super viewDidLoad];
21 |
22 | self.tableView.rowHeight = UITableViewAutomaticDimension;
23 | self.tableView.estimatedRowHeight = 80;
24 |
25 | _allTags = @[
26 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
27 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
28 | @"on", @"constraints", @"placed", @"on", @"those", @"views"
29 | ];
30 | _cellInfos = [NSMutableArray new];
31 | for (NSInteger i = 0; i < 50; i++) {
32 | [_cellInfos addObject:[_allTags subarrayWithRange:NSMakeRange(0, i % (_allTags.count + 1))]];
33 | }
34 | }
35 |
36 | #pragma mark - Table view data source
37 |
38 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
39 | return _cellInfos.count;
40 | }
41 |
42 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
43 | TTGExample4TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([TTGExample4TableViewCell class])
44 | forIndexPath:indexPath];
45 | [cell setTags:_cellInfos[(NSUInteger) indexPath.row]];
46 | cell.label.text = [NSString stringWithFormat:@"Cell: %ld", (long)indexPath.row];
47 |
48 | return cell;
49 | }
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample5ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample5ViewController.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2016/10/16.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TTGExample5ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample5ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample5ViewController.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2016/10/16.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGExample5ViewController.h"
10 | #import
11 |
12 | @interface TTGExample5ViewController ()
13 | @property (weak, nonatomic) IBOutlet TTGTextTagCollectionView *oneLineTagView;
14 | @property (weak, nonatomic) IBOutlet TTGTextTagCollectionView *twoLineTagView;
15 | @property (weak, nonatomic) IBOutlet TTGTextTagCollectionView *threeLineTagView;
16 |
17 | @end
18 |
19 | @implementation TTGExample5ViewController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 |
24 | _oneLineTagView.scrollDirection = TTGTagCollectionScrollDirectionHorizontal;
25 | _twoLineTagView.scrollDirection = TTGTagCollectionScrollDirectionHorizontal;
26 | _threeLineTagView.scrollDirection = TTGTagCollectionScrollDirectionHorizontal;
27 |
28 | _oneLineTagView.alignment = TTGTagCollectionAlignmentFillByExpandingWidth;
29 | _twoLineTagView.alignment = TTGTagCollectionAlignmentFillByExpandingWidth;
30 | _threeLineTagView.alignment = TTGTagCollectionAlignmentFillByExpandingWidth;
31 |
32 | _oneLineTagView.numberOfLines = 1;
33 | _twoLineTagView.numberOfLines = 2;
34 | _threeLineTagView.numberOfLines = 3;
35 |
36 | [_oneLineTagView addTags:[self generateTags]];
37 | [_oneLineTagView reload];
38 |
39 | [_twoLineTagView addTags:[self generateTags]];
40 | [_twoLineTagView reload];
41 |
42 | [_threeLineTagView addTags:[self generateTags]];
43 | [_threeLineTagView reload];
44 | }
45 |
46 | - (NSArray *)generateTags {
47 | NSArray *tags = @[@"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
48 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
49 | @"on", @"constraints", @"placed", @"on", @"those", @"views"];
50 |
51 | NSMutableArray *textTags = [NSMutableArray new];
52 | for (NSString *string in tags) {
53 | TTGTextTag *textTag = [TTGTextTag tagWithContent:[TTGTextTagStringContent contentWithText:string] style:[TTGTextTagStyle new]];
54 | textTag.selectedStyle.backgroundColor = [UIColor greenColor];
55 | [textTags addObject:textTag];
56 | }
57 |
58 | return textTags;
59 | }
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample6ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample6ViewController.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2017/3/2.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TTGExample6ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample6ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample6ViewController.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2017/3/2.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGExample6ViewController.h"
10 | #import
11 | #import
12 |
13 | @interface TTGExample6ViewController ()
14 | @property (weak, nonatomic) IBOutlet TTGTextTagCollectionView *tagView;
15 |
16 | @end
17 |
18 | @implementation TTGExample6ViewController
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 |
23 | __weak typeof(self) weakSelf = self;
24 | [_tagView.scrollView addPullToRefreshWithActionHandler:^{
25 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
26 | [weakSelf.tagView.scrollView.pullToRefreshView stopAnimating];
27 | [weakSelf.tagView removeAllTags];
28 | [weakSelf.tagView addTags:[weakSelf generateTags]];
29 | [weakSelf.tagView reload];
30 | });
31 | }];
32 |
33 | [_tagView.scrollView addInfiniteScrollingWithActionHandler:^{
34 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
35 | [weakSelf.tagView.scrollView.infiniteScrollingView stopAnimating];
36 | [weakSelf.tagView addTags:[weakSelf generateTags]];
37 | [weakSelf.tagView reload];
38 | });
39 | }];
40 |
41 | _tagView.scrollView.infiniteScrollingView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
42 | _tagView.alignment = TTGTagCollectionAlignmentFillByExpandingWidth;
43 | _tagView.scrollView.alwaysBounceVertical = YES; // Very important
44 | [_tagView.scrollView triggerPullToRefresh];
45 | }
46 |
47 | - (NSArray *)generateTags {
48 | NSArray *tags = @[@"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
49 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
50 | @"on", @"constraints", @"placed", @"on", @"those", @"views"];
51 |
52 | NSMutableArray *textTags = [NSMutableArray new];
53 | for (NSString *string in tags) {
54 | TTGTextTag *textTag = [TTGTextTag tagWithContent:[TTGTextTagStringContent contentWithText:string] style:[TTGTextTagStyle new]];
55 | textTag.selectedStyle.backgroundColor = [UIColor greenColor];
56 | [textTags addObject:textTag];
57 | }
58 |
59 | return textTags;
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample7ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample7ViewController.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2017/3/4.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TTGExample7ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample7ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample7ViewController.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2017/3/4.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGExample7ViewController.h"
10 | #import
11 |
12 | @interface TTGExample7ViewController ()
13 | @property (weak, nonatomic) IBOutlet TTGTextTagCollectionView *tagView;
14 | @end
15 |
16 | @implementation TTGExample7ViewController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 |
21 | NSArray *tags = @[@"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
22 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
23 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
24 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
25 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
26 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
27 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
28 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
29 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
30 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
31 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
32 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
33 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
34 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
35 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
36 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
37 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
38 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
39 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
40 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
41 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
42 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
43 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
44 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
45 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
46 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
47 | @"on", @"constraints", @"placed", @"on", @"those", @"views",
48 | @"AutoLayout", @"dynamically", @"calculates", @"the", @"size", @"and", @"position",
49 | @"of", @"all", @"the", @"views", @"in", @"your", @"view", @"hierarchy", @"based",
50 | @"on", @"constraints", @"placed", @"on", @"those", @"views"];
51 |
52 | _tagView.alignment = TTGTagCollectionAlignmentFillByExpandingWidth;
53 |
54 | NSUInteger location = 0;
55 | NSUInteger length = 8;
56 |
57 | [self.class addBatchTagsWithStrings:tags
58 | range:NSMakeRange(location, length)
59 | toTagView:_tagView
60 | backgroundColor:[UIColor colorWithRed:0.24 green:0.72 blue:0.94 alpha:1.00]
61 | attachment:@{@"key": @"1"}];
62 |
63 | location += length;
64 | [self.class addBatchTagsWithStrings:tags
65 | range:NSMakeRange(location, length)
66 | toTagView:_tagView
67 | backgroundColor:[UIColor colorWithRed:0.30 green:0.72 blue:0.53 alpha:1.00]
68 | attachment:@{@"key": @"2"}];
69 |
70 | location += length;
71 | [self.class addBatchTagsWithStrings:tags
72 | range:NSMakeRange(location, length)
73 | toTagView:_tagView
74 | backgroundColor:[UIColor colorWithRed:0.97 green:0.64 blue:0.27 alpha:1.00]
75 | attachment:@{@"key": @"3"}];
76 |
77 | location += length;
78 | [self.class addBatchTagsWithStrings:tags
79 | range:NSMakeRange(location, length)
80 | toTagView:_tagView
81 | backgroundColor:[UIColor colorWithRed:0.73 green:0.91 blue:0.41 alpha:1.00]
82 | attachment:@{@"key": @"4"}];
83 |
84 | location += length;
85 | [self.class addBatchTagsWithStrings:tags
86 | range:NSMakeRange(location, length)
87 | toTagView:_tagView
88 | backgroundColor:[UIColor colorWithRed:0.35 green:0.35 blue:0.36 alpha:1.00]
89 | attachment:@{@"key": @"5"}];
90 |
91 | location += length;
92 | [self.class addBatchTagsWithStrings:tags
93 | range:NSMakeRange(location, length)
94 | toTagView:_tagView
95 | backgroundColor:[UIColor colorWithRed:1.00 green:0.41 blue:0.42 alpha:1.00]
96 | attachment:@{@"key": @"6"}];
97 |
98 | location += length;
99 | [self.class addBatchTagsWithStrings:tags
100 | range:NSMakeRange(location, length)
101 | toTagView:_tagView
102 | backgroundColor:[UIColor colorWithRed:0.50 green:0.86 blue:0.90 alpha:1.00]
103 | attachment:@{@"key": @"7"}];
104 |
105 | location += length;
106 | [self.class addBatchTagsWithStrings:tags
107 | range:NSMakeRange(location, length)
108 | toTagView:_tagView
109 | backgroundColor:[UIColor colorWithRed:0.33 green:0.23 blue:0.34 alpha:1.00]
110 | attachment:@{@"key": @"8"}];
111 |
112 | _tagView.delegate = self;
113 | [_tagView reload];
114 | }
115 |
116 | #pragma mark - TTGTextTagCollectionViewDelegate
117 |
118 | - (void)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView
119 | didTapTag:(TTGTextTag *)tag
120 | atIndex:(NSUInteger)index {
121 | NSLog(@"Did tap: %@, config extra: %@", tag.content, tag.attachment);
122 | }
123 |
124 | + (void)addBatchTagsWithStrings:(NSArray *)strings
125 | range:(NSRange)range
126 | toTagView:(TTGTextTagCollectionView *)tagView
127 | backgroundColor:(UIColor *)backgroundColor
128 | attachment:(id)attachment {
129 |
130 | static TTGTextTagStyle *defaultStyle = nil;
131 | static TTGTextTagStringContent *defaultContent = nil;
132 |
133 | static dispatch_once_t onceToken;
134 | dispatch_once(&onceToken, ^{
135 | defaultStyle = [TTGTextTagStyle new];
136 | defaultStyle.backgroundColor = [UIColor whiteColor];
137 | defaultStyle.borderColor = [UIColor whiteColor];
138 | defaultStyle.borderWidth = 1;
139 | defaultStyle.cornerRadius = 4;
140 | defaultStyle.extraSpace = CGSizeMake(8, 8);
141 | defaultStyle.shadowColor = [UIColor blackColor];
142 | defaultStyle.shadowOpacity = 0.3;
143 | defaultStyle.shadowRadius = 2;
144 | defaultStyle.shadowOffset = CGSizeMake(1, 1);
145 |
146 | defaultContent = [TTGTextTagStringContent new];
147 | defaultContent.textFont = [UIFont systemFontOfSize:20];
148 | defaultContent.textColor = [UIColor whiteColor];
149 | });
150 |
151 | for (NSString *text in [strings subarrayWithRange:range]) {
152 | TTGTextTag *tag = [TTGTextTag new];
153 |
154 | // tag.enableAutoDetectAccessibility = YES;
155 |
156 | tag.isAccessibilityElement = YES;
157 | tag.accessibilityLabel = text;
158 | tag.accessibilityIdentifier = [NSString stringWithFormat:@"identifier: %@", text];
159 | tag.accessibilityHint = [NSString stringWithFormat:@"hint: %@", text];
160 | tag.accessibilityValue = [NSString stringWithFormat:@"value: %@", text];
161 |
162 | TTGTextTagStyle *style = [defaultStyle copy];
163 | style.backgroundColor = backgroundColor;
164 |
165 | TTGTextTagStyle *selectedStyle = [style copy];
166 | selectedStyle.backgroundColor = [self.class getRevertColor:style.backgroundColor];
167 | selectedStyle.borderColor = [UIColor blackColor];
168 | selectedStyle.cornerRadius = 8;
169 | selectedStyle.shadowColor = [UIColor greenColor];
170 |
171 | TTGTextTagStringContent *content = [defaultContent copy];
172 | content.text = text;
173 |
174 | tag.style = style;
175 | tag.selectedStyle = selectedStyle;
176 | tag.content = content;
177 | tag.attachment = attachment;
178 | [tagView addTag:tag];
179 | }
180 |
181 | [tagView updateTagAtIndex:range.location + arc4random_uniform((uint32_t)range.length) selected:YES];
182 | }
183 |
184 | + (UIColor *)getRevertColor:(UIColor *)color {
185 | CGFloat red = 0;
186 | CGFloat green = 0;
187 | CGFloat blue = 0;
188 | [color getRed:&red green:&green blue:&blue alpha:nil];
189 | return [UIColor colorWithRed:1 - red green:1 - green blue:1 - blue alpha:1];
190 | }
191 |
192 | @end
193 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample8ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample8ViewController.h
3 | // TTGTagCollectionView_Example
4 | //
5 | // Created by zekunyan on 24/03/2018.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TTGExample8ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample8ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample8ViewController.m
3 | // TTGTagCollectionView_Example
4 | //
5 | // Created by zekunyan on 24/03/2018.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGExample8ViewController.h"
10 | #import
11 |
12 | #pragma mark - CustomTagData
13 |
14 | @interface CustomTagData: NSObject
15 | @property (nonatomic, strong) NSString *info;
16 | @end
17 |
18 | @implementation CustomTagData
19 | - (NSString *)description {
20 | return [NSString stringWithFormat:@"I am CustomTagData, info is: %@", _info];
21 | }
22 | @end
23 |
24 | #pragma mark - TTGExample8ViewController
25 |
26 | @interface TTGExample8ViewController ()
27 | @property (nonatomic, strong) TTGTextTagCollectionView *tagView;
28 | @property (nonatomic, strong) UITextView *infoTextView;
29 | @end
30 |
31 | @implementation TTGExample8ViewController
32 |
33 | - (void)viewDidLoad {
34 | [super viewDidLoad];
35 |
36 | // Create view
37 | _tagView = [TTGTextTagCollectionView new];
38 | _tagView.alignment = TTGTagCollectionAlignmentFillByExpandingWidth;
39 | _tagView.layer.borderColor = [UIColor grayColor].CGColor;
40 | _tagView.layer.borderWidth = 1;
41 | _tagView.translatesAutoresizingMaskIntoConstraints = NO;
42 | [self.view addSubview:_tagView];
43 |
44 | _infoTextView = [UITextView new];
45 | _infoTextView.layer.borderColor = [UIColor grayColor].CGColor;
46 | _infoTextView.layer.borderWidth = 1;
47 | _infoTextView.textColor = [UIColor grayColor];
48 | _infoTextView.font = [UIFont systemFontOfSize:12];
49 | _infoTextView.translatesAutoresizingMaskIntoConstraints = NO;
50 | _infoTextView.contentInset = UIEdgeInsetsZero;
51 | _infoTextView.textContainerInset = UIEdgeInsetsZero;
52 | _infoTextView.showsHorizontalScrollIndicator = YES;
53 | [self.view addSubview:_infoTextView];
54 |
55 | // TagView Layout
56 | NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[tagView]-20-|"
57 | options:(NSLayoutFormatOptions) 0 metrics:nil
58 | views:@{@"tagView": _tagView}];
59 | NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:_tagView
60 | attribute:NSLayoutAttributeTop
61 | relatedBy:NSLayoutRelationEqual
62 | toItem:self.topLayoutGuide
63 | attribute:NSLayoutAttributeBottom
64 | multiplier:1 constant:20];
65 | [self.view addConstraint:topConstraint];
66 | [self.view addConstraints:hConstraints];
67 |
68 | // Info textView layout
69 | hConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[infoView]-20-|"
70 | options:(NSLayoutFormatOptions) 0 metrics:nil
71 | views:@{@"infoView": _infoTextView}];
72 | topConstraint = [NSLayoutConstraint constraintWithItem:_infoTextView
73 | attribute:NSLayoutAttributeTop
74 | relatedBy:NSLayoutRelationEqual
75 | toItem:_tagView
76 | attribute:NSLayoutAttributeBottom
77 | multiplier:1 constant:20];
78 | NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:_infoTextView
79 | attribute:NSLayoutAttributeBottom
80 | relatedBy:NSLayoutRelationEqual
81 | toItem:self.view
82 | attribute:NSLayoutAttributeBottom
83 | multiplier:1 constant:-20];
84 | [self.view addConstraint:topConstraint];
85 | [self.view addConstraints:hConstraints];
86 | [self.view addConstraint:bottomConstraint];
87 |
88 | TTGTextTagStringContent *defaultContent = [TTGTextTagStringContent new];
89 |
90 | TTGTextTagStyle *defaultStyle = [TTGTextTagStyle new];
91 | defaultStyle.backgroundColor = [UIColor colorWithRed:0.24 green:0.72 blue:0.94 alpha:1.00];
92 | defaultStyle.borderColor = [UIColor whiteColor];
93 | defaultStyle.borderWidth = 1;
94 | defaultStyle.cornerRadius = 4;
95 | defaultStyle.extraSpace = CGSizeMake(8, 8);
96 | defaultStyle.shadowColor = [UIColor blackColor];
97 | defaultStyle.shadowOpacity = 0.3;
98 | defaultStyle.shadowRadius = 2;
99 | defaultStyle.shadowOffset = CGSizeMake(1, 1);
100 |
101 | // Bind CustomTagData
102 | CustomTagData *customTagData = [CustomTagData new];
103 | customTagData.info = @"I am TTGTag custom data.";
104 |
105 | TTGTextTag *tag1 = [TTGTextTag new];
106 | tag1.attachment = customTagData;
107 | tag1.style = defaultStyle;
108 | tag1.content = defaultContent;
109 | ((TTGTextTagStringContent *)tag1.content).text = @"Bind CustomTagData";
110 | [_tagView addTag:tag1];
111 |
112 | // Bind NSDictionary
113 | NSDictionary *dict = @{@"info": @"I am TTGTag NSDictionary data"};
114 |
115 | TTGTextTag *tag2 = [TTGTextTag new];
116 | tag2.attachment = dict;
117 | tag2.style = defaultStyle;
118 | tag2.content = defaultContent;
119 | ((TTGTextTagStringContent *)tag2.content).text = @"Bind NSDictionary";
120 | [_tagView addTag:tag2];
121 |
122 | // Bind String1
123 | TTGTextTag *tag3 = [TTGTextTag new];
124 | tag3.attachment = @"String1";
125 | tag3.style = defaultStyle;
126 | tag3.content = defaultContent;
127 | ((TTGTextTagStringContent *)tag3.content).text = @"Bind String1";
128 | [_tagView addTag:tag3];
129 |
130 | // Bind String2
131 | TTGTextTag *tag4 = [TTGTextTag new];
132 | tag4.attachment = @"String2";
133 | tag4.style = defaultStyle;
134 | tag4.content = defaultContent;
135 | ((TTGTextTagStringContent *)tag4.content).text = @"Bind String2";
136 | [_tagView addTag:tag4];
137 |
138 | // Reload
139 | [_tagView reload];
140 |
141 | // Set delegate
142 | _tagView.delegate = self;
143 | }
144 |
145 | #pragma mark - TTGTextTagCollectionViewDelegate
146 |
147 | - (void)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView
148 | didTapTag:(TTGTextTag *)tag
149 | atIndex:(NSUInteger)index {
150 | _infoTextView.text = [NSString stringWithFormat:@"%@Did Tap:\n%@\n\n", _infoTextView.text, tag.attachment];
151 | }
152 |
153 | @end
154 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample9ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample9ViewController.h
3 | // TTGTagCollectionView_Example
4 | //
5 | // Created by zekunyan on 2021/4/16.
6 | // Copyright © 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TTGExample9ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGExample9ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGExample9ViewController.m
3 | // TTGTagCollectionView_Example
4 | //
5 | // Created by zekunyan on 2021/4/16.
6 | // Copyright © 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGExample9ViewController.h"
10 | #import
11 |
12 | @interface TTGExample9ViewController ()
13 | @property (weak, nonatomic) IBOutlet TTGTextTagCollectionView *textTag;
14 | @end
15 |
16 | @implementation TTGExample9ViewController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 |
21 | // Tag1
22 | NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"Auto Layout dynamically "];
23 |
24 | NSUInteger location = 0;
25 | NSUInteger length = 8;
26 |
27 | [attributedString addAttributes:@{
28 | NSFontAttributeName: [UIFont boldSystemFontOfSize:14],
29 | NSForegroundColorAttributeName: [UIColor blueColor]
30 | } range:NSMakeRange(location, length)];
31 |
32 | location += length;
33 | [attributedString addAttributes:@{
34 | NSFontAttributeName: [UIFont boldSystemFontOfSize:20],
35 | NSForegroundColorAttributeName: [UIColor greenColor],
36 | NSBackgroundColorAttributeName: [UIColor blackColor],
37 | NSStrikethroughStyleAttributeName: @(1)
38 | } range:NSMakeRange(location, length)];
39 |
40 | location += length;
41 | [attributedString addAttributes:@{
42 | NSFontAttributeName: [UIFont italicSystemFontOfSize:16],
43 | NSForegroundColorAttributeName: [UIColor redColor],
44 | NSBackgroundColorAttributeName: [UIColor yellowColor]
45 | } range:NSMakeRange(location, length)];
46 |
47 | TTGTextTag *tag = [TTGTextTag new];
48 | tag.content = [TTGTextTagAttributedStringContent contentWithAttributedText:attributedString];
49 | tag.style = [TTGTextTagStyle new];
50 | [_textTag addTag:tag];
51 |
52 | // Tag2
53 | attributedString = [[NSMutableAttributedString alloc] initWithString:@" calculates the size "];
54 |
55 | location = 0;
56 | [attributedString addAttributes:@{
57 | NSFontAttributeName: [UIFont boldSystemFontOfSize:32],
58 | NSForegroundColorAttributeName: [UIColor orangeColor],
59 | NSBackgroundColorAttributeName: [UIColor darkGrayColor],
60 | NSStrikethroughStyleAttributeName: @(1),
61 | NSStrikethroughColorAttributeName: [UIColor redColor]
62 | } range:NSMakeRange(location, length)];
63 |
64 | location += length;
65 | [attributedString addAttributes:@{
66 | NSFontAttributeName: [UIFont italicSystemFontOfSize:12],
67 | NSForegroundColorAttributeName: [UIColor purpleColor],
68 | NSBackgroundColorAttributeName: [UIColor whiteColor],
69 | NSUnderlineStyleAttributeName: @(1),
70 | NSUnderlineColorAttributeName: [UIColor systemPinkColor]
71 | } range:NSMakeRange(location, length)];
72 |
73 | tag = [TTGTextTag new];
74 | tag.content = [TTGTextTagAttributedStringContent contentWithAttributedText:attributedString];
75 | tag.style = [TTGTextTagStyle new];
76 | [_textTag addTag:tag];
77 |
78 | [_textTag reload];
79 | }
80 |
81 | @end
82 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGTagCollectionView-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | Launch Screen
29 | UIMainStoryboardFile
30 | Main
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UISupportedInterfaceOrientations~ipad
42 |
43 | UIInterfaceOrientationPortrait
44 | UIInterfaceOrientationPortraitUpsideDown
45 | UIInterfaceOrientationLandscapeLeft
46 | UIInterfaceOrientationLandscapeRight
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/TTGTagCollectionView-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #import
8 |
9 | #ifndef __IPHONE_5_0
10 | #warning "This project uses features only available in iOS SDK 5.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | @import UIKit;
15 | @import Foundation;
16 | #endif
17 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/Example/TTGTagCollectionView/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 12/11/2015.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 | #import "TTGAppDelegate.h"
11 |
12 | int main(int argc, char * argv[])
13 | {
14 | @autoreleasepool {
15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([TTGAppDelegate class]));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Example/Tests/Tests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Example/Tests/Tests-Prefix.pch:
--------------------------------------------------------------------------------
1 | // The contents of this file are implicitly included at the beginning of every test case source file.
2 |
3 | #ifdef __OBJC__
4 |
5 |
6 |
7 | #endif
8 |
--------------------------------------------------------------------------------
/Example/Tests/Tests.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTagCollectionViewTests.m
3 | // TTGTagCollectionViewTests
4 | //
5 | // Created by zekunyan on 12/11/2015.
6 | // Copyright (c) 2019 zekunyan. All rights reserved.
7 | //
8 |
9 | @import XCTest;
10 | #import
11 |
12 | @interface Tests : XCTestCase
13 |
14 | @end
15 |
16 | @implementation Tests
17 |
18 | - (void)setUp {
19 | [super setUp];
20 | }
21 |
22 | - (void)tearDown {
23 | [super tearDown];
24 | }
25 |
26 | - (TTGTextTagCollectionView *)getTextCaseTextTagView {
27 | TTGTextTagCollectionView *textTagView = [TTGTextTagCollectionView new];
28 |
29 | for (NSInteger i = 1; i < 10; i++) {
30 | [textTagView addTag:@(i).description];
31 | }
32 |
33 | return textTagView;
34 | }
35 |
36 | - (void)testAddTagAndGetTag {
37 | TTGTextTagCollectionView *textTagView = [TTGTextTagCollectionView new];
38 |
39 | // addTag:
40 | [textTagView addTag:@"1"];
41 | [textTagView addTag:@"2"];
42 |
43 | // addTags:
44 | [textTagView addTags:@[@"3", @"4"]];
45 | [textTagView addTags:@[@"5", @"6"]];
46 |
47 | // addTag:withConfig
48 | TTGTextTag *config = [TTGTextTag new];
49 | config.textFont = [UIFont systemFontOfSize:14];
50 | [textTagView addTag:@"7" withConfig:config];
51 |
52 | // addTags:withConfig:
53 | config.textFont = [UIFont systemFontOfSize:16];
54 | [textTagView addTags:@[@"8", @"9"] withConfig:config];
55 |
56 | // Check
57 | XCTAssert([textTagView allTags].count == 9);
58 | XCTAssert([textTagView allNotSelectedTags].count == 9);
59 | XCTAssert([textTagView allSelectedTags].count == 0);
60 |
61 | XCTAssert([[textTagView getTagAtIndex:1] isEqualToString:@"2"]);
62 | XCTAssert([[textTagView getTagAtIndex:4] isEqualToString:@"5"]);
63 | XCTAssert([textTagView getTagAtIndex:100] == nil);
64 | XCTAssert([textTagView getTagAtIndex:-1] == nil);
65 |
66 | NSArray *tags = [textTagView getTagsInRange:NSMakeRange(1, 2)];
67 | XCTAssert(tags.count == 2);
68 | XCTAssert([tags[0] isEqualToString:@"2"]);
69 | XCTAssert([tags[1] isEqualToString:@"3"]);
70 |
71 | tags = [textTagView getTagsInRange:NSMakeRange(100, 100)];
72 | XCTAssert(tags == nil);
73 |
74 | config = [textTagView getConfigAtIndex:6];
75 | XCTAssert(config.textFont.pointSize == 14);
76 |
77 | config = [textTagView getConfigAtIndex:100];
78 | XCTAssert(config == nil);
79 |
80 | NSArray *configs = [textTagView getConfigsInRange:NSMakeRange(7, 2)];
81 | XCTAssert(configs.count == 2);
82 | XCTAssert(configs[0].textFont.pointSize == 16);
83 | XCTAssert(configs[1].textFont.pointSize == 16);
84 |
85 | configs = [textTagView getConfigsInRange:NSMakeRange(100, 100)];
86 | XCTAssert(configs == nil);
87 | }
88 |
89 | - (void)testInsertTag {
90 | TTGTextTagCollectionView *textTagView = [self getTextCaseTextTagView];
91 | XCTAssert([textTagView allTags].count == 9);
92 |
93 | [textTagView insertTag:@"10" atIndex:0];
94 | XCTAssert([[textTagView getTagAtIndex:0] isEqualToString:@"10"]);
95 |
96 | [textTagView insertTag:@"11" atIndex:100];
97 | [textTagView insertTag:@"11" atIndex:-1];
98 | XCTAssert([textTagView allTags].count == 10);
99 |
100 | [textTagView insertTag:@"12" atIndex:[textTagView allTags].count];
101 | XCTAssert([[textTagView getTagAtIndex:textTagView.allTags.count - 1] isEqualToString:@"12"]);
102 |
103 | textTagView = [self getTextCaseTextTagView];
104 | [textTagView insertTags:@[@"13", @"14"] atIndex:2];
105 | XCTAssert([textTagView allTags].count == 11);
106 | XCTAssert([[textTagView getTagAtIndex:2] isEqualToString:@"13"]);
107 | XCTAssert([[textTagView getTagAtIndex:3] isEqualToString:@"14"]);
108 | XCTAssert([[textTagView getTagAtIndex:4] isEqualToString:@"3"]);
109 |
110 | TTGTextTag *config = [TTGTextTag new];
111 | config.textFont = [UIFont systemFontOfSize:32];
112 | textTagView = [self getTextCaseTextTagView];
113 | [textTagView insertTag:@"15" atIndex:6 withConfig:config];
114 | XCTAssert([textTagView allTags].count == 10);
115 | XCTAssert([textTagView getConfigAtIndex:6].textFont.pointSize == 32);
116 |
117 | textTagView = [self getTextCaseTextTagView];
118 | config.textFont = [UIFont systemFontOfSize:24];
119 | [textTagView insertTags:@[@"16", @"17"] atIndex:5 withConfig:config];
120 | XCTAssert([textTagView getConfigAtIndex:5].textFont.pointSize == [textTagView getConfigAtIndex:6].textFont.pointSize);
121 | }
122 |
123 | - (void)testUpdateTag {
124 | TTGTextTagCollectionView *textTagView = [self getTextCaseTextTagView];
125 | XCTAssert([textTagView allTags].count == 9);
126 |
127 | [textTagView setTagAtIndex:2 selected:YES];
128 | XCTAssert([textTagView allSelectedTags].count == 1);
129 | XCTAssert([[textTagView allSelectedTags].lastObject isEqualToString:@"3"]);
130 |
131 | TTGTextTag *config = [TTGTextTag new];
132 | config.textFont = [UIFont systemFontOfSize:40];
133 | [textTagView setTagAtIndex:2 withConfig:config];
134 | XCTAssert([textTagView getConfigAtIndex:2].textFont.pointSize == 40);
135 |
136 | config.textFont = [UIFont systemFontOfSize:10];
137 | [textTagView setTagsInRange:NSMakeRange(4, 2) withConfig:config];
138 | XCTAssert([textTagView getConfigAtIndex:4].textFont.pointSize == 10);
139 | XCTAssert([textTagView getConfigAtIndex:5].textFont.pointSize == 10);
140 | }
141 |
142 | - (void)testRemoveTag {
143 | TTGTextTagCollectionView *textTagView = [self getTextCaseTextTagView];
144 | XCTAssert([textTagView allTags].count == 9);
145 |
146 | [textTagView addTag:@"1"];
147 | [textTagView addTag:@"1"];
148 | [textTagView addTag:@"1"];
149 | [textTagView addTag:@"1"];
150 | XCTAssert([textTagView allTags].count == 13);
151 |
152 | [textTagView removeTag:@"1"];
153 | XCTAssert([textTagView allTags].count == 8);
154 |
155 | [textTagView removeTagAtIndex:-1];
156 | [textTagView removeTagAtIndex:100];
157 | [textTagView removeTag:@"haha"];
158 | XCTAssert([textTagView allTags].count == 8);
159 |
160 | [textTagView removeTagAtIndex:2];
161 | XCTAssert([textTagView allTags].count == 7);
162 | XCTAssert([[textTagView getTagAtIndex:2] isEqualToString:@"5"]);
163 |
164 | [textTagView removeAllTags];
165 | XCTAssert([textTagView allTags].count == [textTagView allSelectedTags].count);
166 | }
167 |
168 | @end
169 |
170 |
--------------------------------------------------------------------------------
/Example/Tests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/ExampleSwift/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '11.0'
2 |
3 | target 'TTGTagSwiftExample' do
4 | use_frameworks!
5 | pod 'TTGTagCollectionView', :path => '../'
6 | end
7 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | BF6A36C5263BFF81000CB844 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6A36C4263BFF81000CB844 /* AppDelegate.swift */; };
11 | BF6A36C7263BFF81000CB844 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6A36C6263BFF81000CB844 /* SceneDelegate.swift */; };
12 | BF6A36C9263BFF81000CB844 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6A36C8263BFF81000CB844 /* ViewController.swift */; };
13 | BF6A36CC263BFF81000CB844 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF6A36CA263BFF81000CB844 /* Main.storyboard */; };
14 | BF6A36CE263BFF84000CB844 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF6A36CD263BFF84000CB844 /* Assets.xcassets */; };
15 | BF6A36D1263BFF84000CB844 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF6A36CF263BFF84000CB844 /* LaunchScreen.storyboard */; };
16 | C63AADBAC89AF2627CDBE1E0 /* Pods_TTGTagSwiftExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9ABBC9733CA17B850DB303 /* Pods_TTGTagSwiftExample.framework */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | 18FE1A9005B5D818D3FB6510 /* Pods-TTGTagSwiftExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TTGTagSwiftExample.debug.xcconfig"; path = "Target Support Files/Pods-TTGTagSwiftExample/Pods-TTGTagSwiftExample.debug.xcconfig"; sourceTree = ""; };
21 | 6F9ABBC9733CA17B850DB303 /* Pods_TTGTagSwiftExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TTGTagSwiftExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
22 | BB73C78F0F625132A98AF918 /* Pods-TTGTagSwiftExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TTGTagSwiftExample.release.xcconfig"; path = "Target Support Files/Pods-TTGTagSwiftExample/Pods-TTGTagSwiftExample.release.xcconfig"; sourceTree = ""; };
23 | BF6A36C1263BFF81000CB844 /* TTGTagSwiftExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TTGTagSwiftExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
24 | BF6A36C4263BFF81000CB844 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
25 | BF6A36C6263BFF81000CB844 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
26 | BF6A36C8263BFF81000CB844 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
27 | BF6A36CB263BFF81000CB844 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
28 | BF6A36CD263BFF84000CB844 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
29 | BF6A36D0263BFF84000CB844 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
30 | BF6A36D2263BFF84000CB844 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
31 | /* End PBXFileReference section */
32 |
33 | /* Begin PBXFrameworksBuildPhase section */
34 | BF6A36BE263BFF81000CB844 /* Frameworks */ = {
35 | isa = PBXFrameworksBuildPhase;
36 | buildActionMask = 2147483647;
37 | files = (
38 | C63AADBAC89AF2627CDBE1E0 /* Pods_TTGTagSwiftExample.framework in Frameworks */,
39 | );
40 | runOnlyForDeploymentPostprocessing = 0;
41 | };
42 | /* End PBXFrameworksBuildPhase section */
43 |
44 | /* Begin PBXGroup section */
45 | 00DBBB0F1645DB9D63D3DA88 /* Frameworks */ = {
46 | isa = PBXGroup;
47 | children = (
48 | 6F9ABBC9733CA17B850DB303 /* Pods_TTGTagSwiftExample.framework */,
49 | );
50 | name = Frameworks;
51 | sourceTree = "";
52 | };
53 | BF6A36B8263BFF80000CB844 = {
54 | isa = PBXGroup;
55 | children = (
56 | BF6A36C3263BFF81000CB844 /* TTGTagSwiftExample */,
57 | BF6A36C2263BFF81000CB844 /* Products */,
58 | FD59D0F953286C8B13FAE4EA /* Pods */,
59 | 00DBBB0F1645DB9D63D3DA88 /* Frameworks */,
60 | );
61 | sourceTree = "";
62 | };
63 | BF6A36C2263BFF81000CB844 /* Products */ = {
64 | isa = PBXGroup;
65 | children = (
66 | BF6A36C1263BFF81000CB844 /* TTGTagSwiftExample.app */,
67 | );
68 | name = Products;
69 | sourceTree = "";
70 | };
71 | BF6A36C3263BFF81000CB844 /* TTGTagSwiftExample */ = {
72 | isa = PBXGroup;
73 | children = (
74 | BF6A36C4263BFF81000CB844 /* AppDelegate.swift */,
75 | BF6A36C6263BFF81000CB844 /* SceneDelegate.swift */,
76 | BF6A36C8263BFF81000CB844 /* ViewController.swift */,
77 | BF6A36CA263BFF81000CB844 /* Main.storyboard */,
78 | BF6A36CD263BFF84000CB844 /* Assets.xcassets */,
79 | BF6A36CF263BFF84000CB844 /* LaunchScreen.storyboard */,
80 | BF6A36D2263BFF84000CB844 /* Info.plist */,
81 | );
82 | path = TTGTagSwiftExample;
83 | sourceTree = "";
84 | };
85 | FD59D0F953286C8B13FAE4EA /* Pods */ = {
86 | isa = PBXGroup;
87 | children = (
88 | 18FE1A9005B5D818D3FB6510 /* Pods-TTGTagSwiftExample.debug.xcconfig */,
89 | BB73C78F0F625132A98AF918 /* Pods-TTGTagSwiftExample.release.xcconfig */,
90 | );
91 | name = Pods;
92 | path = Pods;
93 | sourceTree = "";
94 | };
95 | /* End PBXGroup section */
96 |
97 | /* Begin PBXNativeTarget section */
98 | BF6A36C0263BFF81000CB844 /* TTGTagSwiftExample */ = {
99 | isa = PBXNativeTarget;
100 | buildConfigurationList = BF6A36D5263BFF84000CB844 /* Build configuration list for PBXNativeTarget "TTGTagSwiftExample" */;
101 | buildPhases = (
102 | 3D80F5748BCA2BA0E353F305 /* [CP] Check Pods Manifest.lock */,
103 | BF6A36BD263BFF81000CB844 /* Sources */,
104 | BF6A36BE263BFF81000CB844 /* Frameworks */,
105 | BF6A36BF263BFF81000CB844 /* Resources */,
106 | 54F7AD8D4F62063FD18B9BE6 /* [CP] Embed Pods Frameworks */,
107 | );
108 | buildRules = (
109 | );
110 | dependencies = (
111 | );
112 | name = TTGTagSwiftExample;
113 | productName = TTGTagSwiftExample;
114 | productReference = BF6A36C1263BFF81000CB844 /* TTGTagSwiftExample.app */;
115 | productType = "com.apple.product-type.application";
116 | };
117 | /* End PBXNativeTarget section */
118 |
119 | /* Begin PBXProject section */
120 | BF6A36B9263BFF80000CB844 /* Project object */ = {
121 | isa = PBXProject;
122 | attributes = {
123 | LastSwiftUpdateCheck = 1250;
124 | LastUpgradeCheck = 1250;
125 | TargetAttributes = {
126 | BF6A36C0263BFF81000CB844 = {
127 | CreatedOnToolsVersion = 12.5;
128 | };
129 | };
130 | };
131 | buildConfigurationList = BF6A36BC263BFF80000CB844 /* Build configuration list for PBXProject "TTGTagSwiftExample" */;
132 | compatibilityVersion = "Xcode 9.3";
133 | developmentRegion = en;
134 | hasScannedForEncodings = 0;
135 | knownRegions = (
136 | en,
137 | Base,
138 | );
139 | mainGroup = BF6A36B8263BFF80000CB844;
140 | productRefGroup = BF6A36C2263BFF81000CB844 /* Products */;
141 | projectDirPath = "";
142 | projectRoot = "";
143 | targets = (
144 | BF6A36C0263BFF81000CB844 /* TTGTagSwiftExample */,
145 | );
146 | };
147 | /* End PBXProject section */
148 |
149 | /* Begin PBXResourcesBuildPhase section */
150 | BF6A36BF263BFF81000CB844 /* Resources */ = {
151 | isa = PBXResourcesBuildPhase;
152 | buildActionMask = 2147483647;
153 | files = (
154 | BF6A36D1263BFF84000CB844 /* LaunchScreen.storyboard in Resources */,
155 | BF6A36CE263BFF84000CB844 /* Assets.xcassets in Resources */,
156 | BF6A36CC263BFF81000CB844 /* Main.storyboard in Resources */,
157 | );
158 | runOnlyForDeploymentPostprocessing = 0;
159 | };
160 | /* End PBXResourcesBuildPhase section */
161 |
162 | /* Begin PBXShellScriptBuildPhase section */
163 | 3D80F5748BCA2BA0E353F305 /* [CP] Check Pods Manifest.lock */ = {
164 | isa = PBXShellScriptBuildPhase;
165 | buildActionMask = 2147483647;
166 | files = (
167 | );
168 | inputFileListPaths = (
169 | );
170 | inputPaths = (
171 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
172 | "${PODS_ROOT}/Manifest.lock",
173 | );
174 | name = "[CP] Check Pods Manifest.lock";
175 | outputFileListPaths = (
176 | );
177 | outputPaths = (
178 | "$(DERIVED_FILE_DIR)/Pods-TTGTagSwiftExample-checkManifestLockResult.txt",
179 | );
180 | runOnlyForDeploymentPostprocessing = 0;
181 | shellPath = /bin/sh;
182 | 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";
183 | showEnvVarsInLog = 0;
184 | };
185 | 54F7AD8D4F62063FD18B9BE6 /* [CP] Embed Pods Frameworks */ = {
186 | isa = PBXShellScriptBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | );
190 | inputFileListPaths = (
191 | "${PODS_ROOT}/Target Support Files/Pods-TTGTagSwiftExample/Pods-TTGTagSwiftExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
192 | );
193 | name = "[CP] Embed Pods Frameworks";
194 | outputFileListPaths = (
195 | "${PODS_ROOT}/Target Support Files/Pods-TTGTagSwiftExample/Pods-TTGTagSwiftExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
196 | );
197 | runOnlyForDeploymentPostprocessing = 0;
198 | shellPath = /bin/sh;
199 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-TTGTagSwiftExample/Pods-TTGTagSwiftExample-frameworks.sh\"\n";
200 | showEnvVarsInLog = 0;
201 | };
202 | /* End PBXShellScriptBuildPhase section */
203 |
204 | /* Begin PBXSourcesBuildPhase section */
205 | BF6A36BD263BFF81000CB844 /* Sources */ = {
206 | isa = PBXSourcesBuildPhase;
207 | buildActionMask = 2147483647;
208 | files = (
209 | BF6A36C9263BFF81000CB844 /* ViewController.swift in Sources */,
210 | BF6A36C5263BFF81000CB844 /* AppDelegate.swift in Sources */,
211 | BF6A36C7263BFF81000CB844 /* SceneDelegate.swift in Sources */,
212 | );
213 | runOnlyForDeploymentPostprocessing = 0;
214 | };
215 | /* End PBXSourcesBuildPhase section */
216 |
217 | /* Begin PBXVariantGroup section */
218 | BF6A36CA263BFF81000CB844 /* Main.storyboard */ = {
219 | isa = PBXVariantGroup;
220 | children = (
221 | BF6A36CB263BFF81000CB844 /* Base */,
222 | );
223 | name = Main.storyboard;
224 | sourceTree = "";
225 | };
226 | BF6A36CF263BFF84000CB844 /* LaunchScreen.storyboard */ = {
227 | isa = PBXVariantGroup;
228 | children = (
229 | BF6A36D0263BFF84000CB844 /* Base */,
230 | );
231 | name = LaunchScreen.storyboard;
232 | sourceTree = "";
233 | };
234 | /* End PBXVariantGroup section */
235 |
236 | /* Begin XCBuildConfiguration section */
237 | BF6A36D3263BFF84000CB844 /* Debug */ = {
238 | isa = XCBuildConfiguration;
239 | buildSettings = {
240 | ALWAYS_SEARCH_USER_PATHS = NO;
241 | CLANG_ANALYZER_NONNULL = YES;
242 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
243 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
244 | CLANG_CXX_LIBRARY = "libc++";
245 | CLANG_ENABLE_MODULES = YES;
246 | CLANG_ENABLE_OBJC_ARC = YES;
247 | CLANG_ENABLE_OBJC_WEAK = YES;
248 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
249 | CLANG_WARN_BOOL_CONVERSION = YES;
250 | CLANG_WARN_COMMA = YES;
251 | CLANG_WARN_CONSTANT_CONVERSION = YES;
252 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
253 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
254 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
255 | CLANG_WARN_EMPTY_BODY = YES;
256 | CLANG_WARN_ENUM_CONVERSION = YES;
257 | CLANG_WARN_INFINITE_RECURSION = YES;
258 | CLANG_WARN_INT_CONVERSION = YES;
259 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
260 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
261 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
262 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
263 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
264 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
265 | CLANG_WARN_STRICT_PROTOTYPES = YES;
266 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
267 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
268 | CLANG_WARN_UNREACHABLE_CODE = YES;
269 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
270 | COPY_PHASE_STRIP = NO;
271 | DEBUG_INFORMATION_FORMAT = dwarf;
272 | ENABLE_STRICT_OBJC_MSGSEND = YES;
273 | ENABLE_TESTABILITY = YES;
274 | GCC_C_LANGUAGE_STANDARD = gnu11;
275 | GCC_DYNAMIC_NO_PIC = NO;
276 | GCC_NO_COMMON_BLOCKS = YES;
277 | GCC_OPTIMIZATION_LEVEL = 0;
278 | GCC_PREPROCESSOR_DEFINITIONS = (
279 | "DEBUG=1",
280 | "$(inherited)",
281 | );
282 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
283 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
284 | GCC_WARN_UNDECLARED_SELECTOR = YES;
285 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
286 | GCC_WARN_UNUSED_FUNCTION = YES;
287 | GCC_WARN_UNUSED_VARIABLE = YES;
288 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
289 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
290 | MTL_FAST_MATH = YES;
291 | ONLY_ACTIVE_ARCH = YES;
292 | SDKROOT = iphoneos;
293 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
294 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
295 | };
296 | name = Debug;
297 | };
298 | BF6A36D4263BFF84000CB844 /* Release */ = {
299 | isa = XCBuildConfiguration;
300 | buildSettings = {
301 | ALWAYS_SEARCH_USER_PATHS = NO;
302 | CLANG_ANALYZER_NONNULL = YES;
303 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
304 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
305 | CLANG_CXX_LIBRARY = "libc++";
306 | CLANG_ENABLE_MODULES = YES;
307 | CLANG_ENABLE_OBJC_ARC = YES;
308 | CLANG_ENABLE_OBJC_WEAK = YES;
309 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
310 | CLANG_WARN_BOOL_CONVERSION = YES;
311 | CLANG_WARN_COMMA = YES;
312 | CLANG_WARN_CONSTANT_CONVERSION = YES;
313 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
314 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
315 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
316 | CLANG_WARN_EMPTY_BODY = YES;
317 | CLANG_WARN_ENUM_CONVERSION = YES;
318 | CLANG_WARN_INFINITE_RECURSION = YES;
319 | CLANG_WARN_INT_CONVERSION = YES;
320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
324 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
326 | CLANG_WARN_STRICT_PROTOTYPES = YES;
327 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
328 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
329 | CLANG_WARN_UNREACHABLE_CODE = YES;
330 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
331 | COPY_PHASE_STRIP = NO;
332 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
333 | ENABLE_NS_ASSERTIONS = NO;
334 | ENABLE_STRICT_OBJC_MSGSEND = YES;
335 | GCC_C_LANGUAGE_STANDARD = gnu11;
336 | GCC_NO_COMMON_BLOCKS = YES;
337 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
338 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
339 | GCC_WARN_UNDECLARED_SELECTOR = YES;
340 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
341 | GCC_WARN_UNUSED_FUNCTION = YES;
342 | GCC_WARN_UNUSED_VARIABLE = YES;
343 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
344 | MTL_ENABLE_DEBUG_INFO = NO;
345 | MTL_FAST_MATH = YES;
346 | SDKROOT = iphoneos;
347 | SWIFT_COMPILATION_MODE = wholemodule;
348 | SWIFT_OPTIMIZATION_LEVEL = "-O";
349 | VALIDATE_PRODUCT = YES;
350 | };
351 | name = Release;
352 | };
353 | BF6A36D6263BFF84000CB844 /* Debug */ = {
354 | isa = XCBuildConfiguration;
355 | baseConfigurationReference = 18FE1A9005B5D818D3FB6510 /* Pods-TTGTagSwiftExample.debug.xcconfig */;
356 | buildSettings = {
357 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
358 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
359 | CODE_SIGN_STYLE = Automatic;
360 | INFOPLIST_FILE = TTGTagSwiftExample/Info.plist;
361 | LD_RUNPATH_SEARCH_PATHS = (
362 | "$(inherited)",
363 | "@executable_path/Frameworks",
364 | );
365 | PRODUCT_BUNDLE_IDENTIFIER = me.tutuge.swift.TTGTagSwiftExample;
366 | PRODUCT_NAME = "$(TARGET_NAME)";
367 | SWIFT_VERSION = 5.0;
368 | TARGETED_DEVICE_FAMILY = "1,2";
369 | };
370 | name = Debug;
371 | };
372 | BF6A36D7263BFF84000CB844 /* Release */ = {
373 | isa = XCBuildConfiguration;
374 | baseConfigurationReference = BB73C78F0F625132A98AF918 /* Pods-TTGTagSwiftExample.release.xcconfig */;
375 | buildSettings = {
376 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
377 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
378 | CODE_SIGN_STYLE = Automatic;
379 | INFOPLIST_FILE = TTGTagSwiftExample/Info.plist;
380 | LD_RUNPATH_SEARCH_PATHS = (
381 | "$(inherited)",
382 | "@executable_path/Frameworks",
383 | );
384 | PRODUCT_BUNDLE_IDENTIFIER = me.tutuge.swift.TTGTagSwiftExample;
385 | PRODUCT_NAME = "$(TARGET_NAME)";
386 | SWIFT_VERSION = 5.0;
387 | TARGETED_DEVICE_FAMILY = "1,2";
388 | };
389 | name = Release;
390 | };
391 | /* End XCBuildConfiguration section */
392 |
393 | /* Begin XCConfigurationList section */
394 | BF6A36BC263BFF80000CB844 /* Build configuration list for PBXProject "TTGTagSwiftExample" */ = {
395 | isa = XCConfigurationList;
396 | buildConfigurations = (
397 | BF6A36D3263BFF84000CB844 /* Debug */,
398 | BF6A36D4263BFF84000CB844 /* Release */,
399 | );
400 | defaultConfigurationIsVisible = 0;
401 | defaultConfigurationName = Release;
402 | };
403 | BF6A36D5263BFF84000CB844 /* Build configuration list for PBXNativeTarget "TTGTagSwiftExample" */ = {
404 | isa = XCConfigurationList;
405 | buildConfigurations = (
406 | BF6A36D6263BFF84000CB844 /* Debug */,
407 | BF6A36D7263BFF84000CB844 /* Release */,
408 | );
409 | defaultConfigurationIsVisible = 0;
410 | defaultConfigurationName = Release;
411 | };
412 | /* End XCConfigurationList section */
413 | };
414 | rootObject = BF6A36B9263BFF80000CB844 /* Project object */;
415 | }
416 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // TTGTagSwiftExample
4 | //
5 | // Created by zekunyan on 2021/4/30.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 |
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UIApplicationSupportsIndirectInputEvents
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIMainStoryboardFile
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationLandscapeLeft
56 | UIInterfaceOrientationLandscapeRight
57 |
58 | UISupportedInterfaceOrientations~ipad
59 |
60 | UIInterfaceOrientationPortrait
61 | UIInterfaceOrientationPortraitUpsideDown
62 | UIInterfaceOrientationLandscapeLeft
63 | UIInterfaceOrientationLandscapeRight
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // TTGTagSwiftExample
4 | //
5 | // Created by zekunyan on 2021/4/30.
6 | //
7 |
8 | import UIKit
9 |
10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
11 |
12 | var window: UIWindow?
13 |
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
19 | guard let _ = (scene as? UIWindowScene) else { return }
20 | }
21 |
22 | func sceneDidDisconnect(_ scene: UIScene) {
23 | // Called as the scene is being released by the system.
24 | // This occurs shortly after the scene enters the background, or when its session is discarded.
25 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
27 | }
28 |
29 | func sceneDidBecomeActive(_ scene: UIScene) {
30 | // Called when the scene has moved from an inactive state to an active state.
31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
32 | }
33 |
34 | func sceneWillResignActive(_ scene: UIScene) {
35 | // Called when the scene will move from an active state to an inactive state.
36 | // This may occur due to temporary interruptions (ex. an incoming phone call).
37 | }
38 |
39 | func sceneWillEnterForeground(_ scene: UIScene) {
40 | // Called as the scene transitions from the background to the foreground.
41 | // Use this method to undo the changes made on entering the background.
42 | }
43 |
44 | func sceneDidEnterBackground(_ scene: UIScene) {
45 | // Called as the scene transitions from the foreground to the background.
46 | // Use this method to save data, release shared resources, and store enough scene-specific state information
47 | // to restore the scene back to its current state.
48 | }
49 |
50 |
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/ExampleSwift/TTGTagSwiftExample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // TTGTagSwiftExample
4 | //
5 | // Created by zekunyan on 2021/4/30.
6 | //
7 |
8 | import UIKit
9 | import TTGTags
10 |
11 | class ViewController: UIViewController {
12 | override func viewDidLoad() {
13 | super.viewDidLoad()
14 |
15 | let tagView = TTGTextTagCollectionView.init(frame: CGRect.init(x: 16, y: 100, width: UIScreen.main.bounds.width - 32, height: 300))
16 | tagView.backgroundColor = UIColor.lightGray
17 | self.view.addSubview(tagView)
18 |
19 | let strings = ["AutoLayout", "dynamically", "calculates", "the", "size", "and", "position",
20 | "of", "all", "the", "views", "in", "your", "view", "hierarchy", "based",
21 | "on", "constraints", "placed", "on", "those", "views"]
22 |
23 | for text in strings {
24 | let content = TTGTextTagStringContent.init(text: text)
25 | content.textColor = UIColor.black
26 | content.textFont = UIFont.boldSystemFont(ofSize: 20)
27 |
28 | let normalStyle = TTGTextTagStyle.init()
29 | normalStyle.backgroundColor = UIColor.white
30 | normalStyle.extraSpace = CGSize.init(width: 8, height: 8)
31 |
32 | let selectedStyle = TTGTextTagStyle.init()
33 | selectedStyle.backgroundColor = UIColor.green
34 | selectedStyle.extraSpace = CGSize.init(width: 8, height: 8)
35 |
36 | let tag = TTGTextTag.init()
37 | tag.content = content
38 | tag.style = normalStyle
39 | tag.selectedStyle = selectedStyle
40 |
41 | tagView.addTag(tag)
42 | }
43 |
44 | tagView.reload()
45 | }
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 zekunyan
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "TTGTags",
7 | platforms: [.iOS(.v11)],
8 | products: [
9 | .library(
10 | name: "TTGTags",
11 | targets: ["TTGTags"]),
12 | ],
13 | dependencies: [],
14 | targets: [
15 | .target(
16 | name: "TTGTags",
17 | path: "Sources",
18 | publicHeadersPath: ""
19 | ),
20 | ]
21 | )
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TTGTagCollectionView
2 | ✨Learn it by DeepWiki✨: [https://deepwiki.com/zekunyan/TTGTagCollectionView/1-overview](https://deepwiki.com/zekunyan/TTGTagCollectionView/1-overview)
3 |
4 | [](https://travis-ci.org/zekunyan/TTGTagCollectionView)
5 | [](http://cocoapods.org/pods/TTGTagCollectionView)
6 | [](http://cocoapods.org/pods/TTGTagCollectionView)
7 | [](http://cocoapods.org/pods/TTGTagCollectionView)
8 | [](https://github.com/zekunyan/TTGTagCollectionView)
9 | [](https://github.com/zekunyan/TTGTagCollectionView)
10 |
11 | 
12 |
13 | 
14 |
15 | ## What
16 |
17 | `TTGTagCollectionView` is useful for showing different size tag views in a vertical or horizontal scrollable view. And if you only want to show text tags, you can use `TTGTextTagCollectionView` instead, which has more simple api. At the same time, It is highly customizable that many features of the text tag can be configured, like the tag font size and the background color.
18 |
19 | ## Features
20 |
21 | * Both rich style text tag and custom view tag supported.
22 | * Highly customizable, each text tag can be configured.
23 | * Vertical and horizontal scrollable.
24 | * Support `NSAttributedString` rich text tag.
25 | * Support different kinds of alignment types.
26 | * Support specifying number of lines.
27 | * Support Autolayout `intrinsicContentSize` to auto determine height based on content size.
28 | * Support pull to refresh, like `SVPullToRefresh`.
29 | * Use `preferredMaxLayoutWidth` to set available width like UIlabel.
30 | * Support `CocoaPods` and `Swift Package Manager`
31 |
32 | ## Demo
33 |
34 | You can find demos in the `Example->TTGTagCollectionView.xcworkspace` or `ExampleSwift->TTGTagSwiftExample.xcworkspace` project.
35 | Run `pod update` before try it.
36 |
37 | 
38 |
39 | ## Code Structure
40 |
41 | 
42 |
43 | ## Requirements
44 |
45 | iOS 9 and later.
46 |
47 | ## Installation
48 |
49 | ### CocoaPods for Objective-C
50 | ```ruby
51 | pod "TTGTagCollectionView"
52 | ```
53 |
54 | ### CocoaPods for Swift
55 | ```ruby
56 | use_frameworks!
57 | pod "TTGTagCollectionView"
58 | ```
59 |
60 | ### Swift Package Manager
61 | Add by `git@github.com:zekunyan/TTGTagCollectionView.git`
62 |
63 | ## Usage
64 |
65 | ### TTGTextTagCollectionView
66 |
67 | Use `TTGTextTagCollectionView` to show text tags.
68 |
69 | #### Basic usage
70 |
71 | ##### Swift
72 |
73 | ```swift
74 | // import
75 | import TTGTags
76 | // Create TTGTextTagCollectionView view
77 | let tagView = TTGTextTagCollectionView.init(frame: CGRect(x: 20, y: 100, width: 200, height: 200))
78 | self.view .addSubview(tagView)
79 | // Create TTGTextTag object
80 | let textTag = TTGTextTag(content: TTGTextTagStringContent(text: "tutuge"), style: TTGTextTagStyle())
81 | // Add tag
82 | tagView.addTag(textTag)
83 | // !!! Never forget this !!!
84 | tagView.reload()
85 | ```
86 |
87 | ##### Objective-C
88 |
89 | ```Objective-C
90 | // import
91 | #import
92 | // Create TTGTextTagCollectionView view
93 | TTGTextTagCollectionView *tagCollectionView = [[TTGTextTagCollectionView alloc] initWithFrame:CGRectMake(20, 20, 200, 200)];
94 | [self.view addSubview:tagCollectionView];
95 | // Create TTGTextTag object
96 | TTGTextTag *textTag = [TTGTextTag tagWithContent:[TTGTextTagStringContent contentWithText:@"Some text"] style:[TTGTextTagStyle new]];
97 | // Add tag
98 | [tagCollectionView addTag:textTag];
99 | // !!! Never forget this !!!
100 | [tagCollectionView reload];
101 | ```
102 |
103 | ##### Accessibility
104 |
105 | ```Objective-C
106 | // Auto set accessibilityLabel value
107 | tag.enableAutoDetectAccessibility = YES;
108 |
109 | // Manual
110 | tag.isAccessibilityElement = YES;
111 | tag.accessibilityLabel = text;
112 | tag.accessibilityIdentifier = [NSString stringWithFormat:@"identifier: %@", text];
113 | tag.accessibilityHint = [NSString stringWithFormat:@"hint: %@", text];
114 | tag.accessibilityValue = [NSString stringWithFormat:@"value: %@", text];
115 | ```
116 |
117 | #### Delegate
118 |
119 | Conform the `TTGTextTagCollectionViewDelegate` protocol to get callback when you select the tag or content height changes.
120 |
121 | ```Objective-C
122 | @protocol TTGTextTagCollectionViewDelegate
123 | @optional
124 | - (BOOL)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView
125 | canTapTag:(TTGTextTag *)tag
126 | atIndex:(NSUInteger)index;
127 |
128 | - (void)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView
129 | didTapTag:(TTGTextTag *)tag
130 | atIndex:(NSUInteger)index;
131 |
132 | - (void)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView
133 | updateContentSize:(CGSize)contentSize;
134 | @end
135 | ```
136 |
137 | #### Customization
138 |
139 | Each tag can be configured.
140 |
141 | ```Objective-C
142 | @interface TTGTextTag : NSObject
143 |
144 | /// ID
145 | @property (nonatomic, assign, readonly) NSUInteger tagId; // Auto increase. The only identifier and main key for a tag
146 |
147 | /// Attachment object. You can use this to bind any object you want to each tag.
148 | @property (nonatomic, strong) id _Nullable attachment;
149 |
150 | /// Normal state content and style
151 | @property (nonatomic, copy) TTGTextTagContent * _Nonnull content;
152 | @property (nonatomic, copy) TTGTextTagStyle * _Nonnull style;
153 |
154 | /// Selected state content and style
155 | @property (nonatomic, copy) TTGTextTagContent * _Nullable selectedContent;
156 | @property (nonatomic, copy) TTGTextTagStyle * _Nullable selectedStyle;
157 |
158 | /// Selection state
159 | @property (nonatomic, assign) BOOL selected;
160 | @property (nonatomic, copy) OnSelectStateChanged _Nullable onSelectStateChanged; // State changed callback
161 |
162 | /// Accessibility
163 | @property (nonatomic, assign) BOOL isAccessibilityElement; // Default = NO
164 | @property (nonatomic, copy) NSString * _Nullable accessibilityIdentifier; // Default = nil
165 | @property (nonatomic, copy) NSString * _Nullable accessibilityLabel; // Default = nil
166 | @property (nonatomic, copy) NSString * _Nullable accessibilityHint; // Default = nil
167 | @property (nonatomic, copy) NSString * _Nullable accessibilityValue; // Default = nil
168 | @property (nonatomic, assign) UIAccessibilityTraits accessibilityTraits; // Default = UIAccessibilityTraitNone
169 |
170 | /// Auto detect accessibility
171 | /// When enableAutoDetectAccessibility = YES, the property below will be set automatically
172 | /// ----------------------------
173 | /// isAccessibilityElement = YES
174 | /// accessibilityLabel = (selected ? selectedContent : content).getContentAttributedString.string
175 | /// accessibilityTraits = selected ? UIAccessibilityTraitSelected : UIAccessibilityTraitButton
176 | /// ----------------------------
177 | /// But: accessibilityHint and accessibilityValue still keep your custom value;
178 | @property (nonatomic, assign) BOOL enableAutoDetectAccessibility; // Default = NO
179 |
180 | @end
181 | ```
182 |
183 | `TTGTextTagContent` has two sub classes.
184 |
185 | ```Objective-C
186 | // Normal Text
187 | @interface TTGTextTagStringContent : TTGTextTagContent
188 | /// Text
189 | @property (nonatomic, copy) NSString * _Nonnull text;
190 | /// Text font
191 | @property (nonatomic, copy) UIFont * _Nonnull textFont;
192 | /// Text color
193 | @property (nonatomic, copy) UIColor * _Nonnull textColor;
194 | @end
195 |
196 | // NSAttributedString Text
197 | @interface TTGTextTagAttributedStringContent : TTGTextTagContent
198 | /// Attributed text
199 | @property (nonatomic, copy) NSAttributedString * _Nonnull attributedText;
200 | @end
201 | ```
202 |
203 | Config `TTGTextTagStyle` if you want to change tag styles.
204 |
205 | ```Objective-C
206 | @interface TTGTextTagStyle : NSObject
207 |
208 | /// Background color
209 | @property (nonatomic, copy) UIColor * _Nonnull backgroundColor; // Default is [UIColor lightGrayColor]
210 |
211 | /// Text alignment
212 | @property (nonatomic, assign) NSTextAlignment textAlignment; // Default is NSTextAlignmentCenter
213 |
214 | /// Gradient background color
215 | @property (nonatomic, assign) BOOL enableGradientBackground; // Default is NO
216 | @property (nonatomic, copy) UIColor * _Nonnull gradientBackgroundStartColor;
217 | @property (nonatomic, copy) UIColor * _Nonnull gradientBackgroundEndColor;
218 | @property (nonatomic, assign) CGPoint gradientBackgroundStartPoint;
219 | @property (nonatomic, assign) CGPoint gradientBackgroundEndPoint;
220 |
221 | /// Corner radius
222 | @property (nonatomic, assign) CGFloat cornerRadius; // Default is 4
223 | @property (nonatomic, assign) Boolean cornerTopRight;
224 | @property (nonatomic, assign) Boolean cornerTopLeft;
225 | @property (nonatomic, assign) Boolean cornerBottomRight;
226 | @property (nonatomic, assign) Boolean cornerBottomLeft;
227 |
228 | /// Border
229 | @property (nonatomic, assign) CGFloat borderWidth; // Default is [UIColor whiteColor]
230 | @property (nonatomic, copy) UIColor * _Nonnull borderColor; // Default is 1
231 |
232 | /// Shadow.
233 | @property (nonatomic, copy) UIColor * _Nonnull shadowColor; // Default is [UIColor blackColor]
234 | @property (nonatomic, assign) CGSize shadowOffset; // Default is (2, 2)
235 | @property (nonatomic, assign) CGFloat shadowRadius; // Default is 2f
236 | @property (nonatomic, assign) CGFloat shadowOpacity; // Default is 0.3f
237 |
238 | /// Extra space in width and height, will expand each tag's size
239 | @property (nonatomic, assign) CGSize extraSpace;
240 |
241 | /// Max width for a text tag. 0 and below means no max width.
242 | @property (nonatomic, assign) CGFloat maxWidth;
243 | /// Min width for a text tag. 0 and below means no min width.
244 | @property (nonatomic, assign) CGFloat minWidth;
245 |
246 | /// Max height for a text tag. 0 and below means no max height.
247 | @property (nonatomic, assign) CGFloat maxHeight;
248 | /// Min height for a text tag. 0 and below means no min height.
249 | @property (nonatomic, assign) CGFloat minHeight;
250 |
251 | /// Exact width. 0 and below means no work
252 | @property (nonatomic, assign) CGFloat exactWidth;
253 | /// Exact height. 0 and below means no work
254 | @property (nonatomic, assign) CGFloat exactHeight;
255 |
256 | @end
257 | ```
258 |
259 | You can also configure scroll direction, alignment, lines limit, spacing and inset.
260 |
261 | ```Objective-C
262 | // TTGTextTagCollectionView.h
263 | // Define if the tag can be selected.
264 | @property (assign, nonatomic) BOOL enableTagSelection;
265 |
266 | // Tags scroll direction, default is vertical.
267 | @property (nonatomic, assign) TTGTagCollectionScrollDirection scrollDirection;
268 |
269 | // Tags layout alignment, default is left.
270 | @property (nonatomic, assign) TTGTagCollectionAlignment alignment;
271 |
272 | // Number of lines. 0 means no limit, default is 0 for vertical and 1 for horizontal.
273 | @property (nonatomic, assign) NSUInteger numberOfLines;
274 |
275 | // Tag selection limit, default is 0, means no limit
276 | @property (nonatomic, assign) NSUInteger selectionLimit;
277 |
278 | // Horizontal and vertical space between tags, default is 4.
279 | @property (assign, nonatomic) CGFloat horizontalSpacing;
280 | @property (assign, nonatomic) CGFloat verticalSpacing;
281 |
282 | // Content inset, default is UIEdgeInsetsMake(2, 2, 2, 2).
283 | @property (nonatomic, assign) UIEdgeInsets contentInset;
284 |
285 | // The true tags content size, readonly
286 | @property (nonatomic, assign, readonly) CGSize contentSize;
287 |
288 | // Manual content height
289 | // Default = NO, set will update content
290 | @property (nonatomic, assign) BOOL manualCalculateHeight;
291 | // Default = 0, set will update content
292 | @property (nonatomic, assign) CGFloat preferredMaxLayoutWidth;
293 |
294 | // Scroll indicator
295 | @property (nonatomic, assign) BOOL showsHorizontalScrollIndicator;
296 | @property (nonatomic, assign) BOOL showsVerticalScrollIndicator;
297 | ```
298 |
299 | Alignment types:
300 |
301 | ```Objective-C
302 | typedef NS_ENUM(NSInteger, TTGTagCollectionAlignment) {
303 | TTGTagCollectionAlignmentLeft = 0, // Default
304 | TTGTagCollectionAlignmentCenter, // Center
305 | TTGTagCollectionAlignmentRight, // Right
306 | TTGTagCollectionAlignmentFillByExpandingSpace, // Expand horizontal spacing and fill
307 | TTGTagCollectionAlignmentFillByExpandingWidth, // Expand width and fill
308 | TTGTagCollectionAlignmentFillByExpandingWidthExceptLastLine, // Expand width and fill, except last line
309 | };
310 | ```
311 |
312 | #### Modify tags
313 |
314 | Add tag.
315 |
316 | ```Objective-C
317 | // TTGTextTagCollectionView.h
318 | /// Add
319 | - (void)addTag:(TTGTextTag *)tag;
320 | - (void)addTags:(NSArray *)tags;
321 | ```
322 |
323 | Insert tag.
324 |
325 | ```Objective-C
326 | // TTGTextTagCollectionView.h
327 | /// Insert
328 | - (void)insertTag:(TTGTextTag *)tag atIndex:(NSUInteger)index;
329 | - (void)insertTags:(NSArray *)tags atIndex:(NSUInteger)index;
330 | ```
331 |
332 | Update tag.
333 |
334 | ```Objective-C
335 | // TTGTextTagCollectionView.h
336 | /// Update
337 | - (void)updateTagAtIndex:(NSUInteger)index selected:(BOOL)selected;
338 | - (void)updateTagAtIndex:(NSUInteger)index withNewTag:(TTGTextTag *)tag;
339 | ```
340 |
341 | Remove tag.
342 |
343 | ```Objective-C
344 | // TTGTextTagCollectionView.h
345 | // Remove tag
346 | - (void)removeTag:(TTGTextTag *)tag;
347 | - (void)removeTagById:(NSUInteger)tagId;
348 | - (void)removeTagAtIndex:(NSUInteger)index;
349 | - (void)removeAllTags;
350 | ```
351 |
352 | Get tags.
353 |
354 | ```Objective-C
355 | // TTGTextTagCollectionView.h
356 | /// Get tag
357 | - (TTGTextTag *)getTagAtIndex:(NSUInteger)index;
358 | - (NSArray *)getTagsInRange:(NSRange)range;
359 |
360 | /// Get all
361 | - (NSArray *)allTags;
362 | - (NSArray *)allSelectedTags;
363 | - (NSArray *)allNotSelectedTags;
364 | ```
365 |
366 | #### Reload
367 |
368 | You can reload tags programmatically.
369 |
370 | ```Objective-C
371 | // TTGTextTagCollectionView.h
372 | - (void)reload;
373 | ```
374 |
375 | #### Index at point
376 |
377 | Returns the index of the tag located at the specified point.
378 |
379 | ```Objective-C
380 | // TTGTextTagCollectionView.h
381 | - (NSInteger)indexOfTagAt:(CGPoint)point;
382 | ```
383 |
384 | ### TTGTagCollectionView
385 |
386 | Use `TTGTagCollectionView` to show custom tag views.
387 |
388 | #### DataSource and Delegate
389 |
390 | Just like the UITableView, you must conform and implement the required methods of `TTGTagCollectionViewDelegate` and `TTGTagCollectionViewDataSource` to get `TTGTagCollectionView` work.
391 |
392 | **DataSource**
393 |
394 | ```Objective-C
395 | @protocol TTGTagCollectionViewDataSource
396 | @required
397 | - (NSUInteger)numberOfTagsInTagCollectionView:(TTGTagCollectionView *)tagCollectionView;
398 |
399 | - (UIView *)tagCollectionView:(TTGTagCollectionView *)tagCollectionView tagViewForIndex:(NSUInteger)index;
400 | @end
401 | ```
402 |
403 | **Delegate**
404 |
405 | ```Objective-C
406 | @protocol TTGTagCollectionViewDelegate
407 | @required
408 | - (CGSize)tagCollectionView:(TTGTagCollectionView *)tagCollectionView sizeForTagAtIndex:(NSUInteger)index;
409 |
410 | @optional
411 | - (BOOL)tagCollectionView:(TTGTagCollectionView *)tagCollectionView shouldSelectTag:(UIView *)tagView atIndex:(NSUInteger)index;
412 |
413 | - (void)tagCollectionView:(TTGTagCollectionView *)tagCollectionView didSelectTag:(UIView *)tagView atIndex:(NSUInteger)index;
414 |
415 | - (void)tagCollectionView:(TTGTagCollectionView *)tagCollectionView updateContentSize:(CGSize)contentSize;
416 | @end
417 | ```
418 |
419 | #### Customization
420 |
421 | ```Objective-C
422 | // TTGTagCollectionView.h
423 | // Tags scroll direction, default is vertical.
424 | @property (nonatomic, assign) TTGTagCollectionScrollDirection scrollDirection;
425 |
426 | // Tags layout alignment, default is left.
427 | @property (nonatomic, assign) TTGTagCollectionAlignment alignment;
428 |
429 | // Number of lines. 0 means no limit, default is 0 for vertical and 1 for horizontal.
430 | @property (nonatomic, assign) NSUInteger numberOfLines;
431 |
432 | // Horizontal and vertical space between tags, default is 4.
433 | @property (nonatomic, assign) CGFloat horizontalSpacing;
434 | @property (nonatomic, assign) CGFloat verticalSpacing;
435 |
436 | // Content inset, default is UIEdgeInsetsMake(2, 2, 2, 2).
437 | @property (nonatomic, assign) UIEdgeInsets contentInset;
438 |
439 | // The true tags content size, readonly
440 | @property (nonatomic, assign, readonly) CGSize contentSize;
441 |
442 | // Manual content height
443 | // Default = NO, set will update content
444 | @property (nonatomic, assign) BOOL manualCalculateHeight;
445 | // Default = 0, set will update content
446 | @property (nonatomic, assign) CGFloat preferredMaxLayoutWidth;
447 |
448 | // Scroll indicator
449 | @property (nonatomic, assign) BOOL showsHorizontalScrollIndicator;
450 | @property (nonatomic, assign) BOOL showsVerticalScrollIndicator;
451 | ```
452 |
453 | #### Reload
454 |
455 | You can reload tags programmatically.
456 |
457 | ```Objective-C
458 | // TTGTagCollectionView.h
459 | - (void)reload;
460 | ```
461 |
462 | #### Index at point
463 |
464 | Returns the index of the tag located at the specified point.
465 |
466 | ```Objective-C
467 | // TTGTagCollectionView.h
468 | - (NSInteger)indexOfTagAt:(CGPoint)point;
469 | ```
470 |
471 | ## Fix
472 |
473 | `UITableViewAutomaticDimension` may not work when using tagView in tableViewCell. You should reload your tableView in the `viewDidAppear`.
474 |
475 | ## Author
476 |
477 | zekunyan, zekunyan@163.com
478 |
479 | ## License
480 |
481 | TTGTagCollectionView is available under the MIT license. See the LICENSE file for more info.
482 |
--------------------------------------------------------------------------------
/Resources/alignment_type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Resources/alignment_type.png
--------------------------------------------------------------------------------
/Resources/code_structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Resources/code_structure.png
--------------------------------------------------------------------------------
/Resources/demo_example.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Resources/demo_example.jpeg
--------------------------------------------------------------------------------
/Resources/screen_shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zekunyan/TTGTagCollectionView/fd3c41c81a23481c3bde2dbdc81844ff1f750fc9/Resources/screen_shot.png
--------------------------------------------------------------------------------
/Sources/TTGTagCollectionView-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTagCollectionView-Bridging-Header.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2021/4/21.
6 | //
7 |
8 | #ifndef TTGTagCollectionView_Bridging_Header_h
9 | #define TTGTagCollectionView_Bridging_Header_h
10 |
11 | #import "TTGTagCollectionView.h"
12 | #import "TTGTextTagCollectionView.h"
13 | #import "TTGTextTag.h"
14 | #import "TTGTextTagContent.h"
15 | #import "TTGTextTagStringContent.h"
16 | #import "TTGTextTagAttributedStringContent.h"
17 | #import "TTGTextTagStyle.h"
18 |
19 | #endif /* TTGTagCollectionView_Bridging_Header_h */
20 |
--------------------------------------------------------------------------------
/Sources/TTGTagCollectionView.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTagCollectionView.h
3 | // Pods
4 | //
5 | // Created by zekunyan on 15/12/26.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class TTGTagCollectionView;
12 |
13 | /**
14 | * Tags scroll direction
15 | */
16 | typedef NS_ENUM(NSInteger, TTGTagCollectionScrollDirection) {
17 | TTGTagCollectionScrollDirectionVertical = 0, // Default
18 | TTGTagCollectionScrollDirectionHorizontal = 1
19 | };
20 |
21 | /**
22 | * Tags alignment
23 | */
24 | typedef NS_ENUM(NSInteger, TTGTagCollectionAlignment) {
25 | TTGTagCollectionAlignmentLeft = 0, // Default
26 | TTGTagCollectionAlignmentCenter, // Center
27 | TTGTagCollectionAlignmentRight, // Right
28 | TTGTagCollectionAlignmentFillByExpandingSpace, // Expand horizontal spacing and fill
29 | TTGTagCollectionAlignmentFillByExpandingWidth, // Expand width and fill
30 | TTGTagCollectionAlignmentFillByExpandingWidthExceptLastLine // Expand width and fill, except last line
31 | };
32 |
33 | /**
34 | * Tags delegate
35 | */
36 | @protocol TTGTagCollectionViewDelegate
37 | @required
38 | - (CGSize)tagCollectionView:(TTGTagCollectionView *)tagCollectionView sizeForTagAtIndex:(NSUInteger)index;
39 |
40 | @optional
41 | - (BOOL)tagCollectionView:(TTGTagCollectionView *)tagCollectionView shouldSelectTag:(UIView *)tagView atIndex:(NSUInteger)index;
42 |
43 | - (void)tagCollectionView:(TTGTagCollectionView *)tagCollectionView didSelectTag:(UIView *)tagView atIndex:(NSUInteger)index;
44 |
45 | - (void)tagCollectionView:(TTGTagCollectionView *)tagCollectionView updateContentSize:(CGSize)contentSize;
46 | @end
47 |
48 | /**
49 | * Tags dataSource
50 | */
51 | @protocol TTGTagCollectionViewDataSource
52 | @required
53 | - (NSUInteger)numberOfTagsInTagCollectionView:(TTGTagCollectionView *)tagCollectionView;
54 |
55 | - (UIView *)tagCollectionView:(TTGTagCollectionView *)tagCollectionView tagViewForIndex:(NSUInteger)index;
56 | @end
57 |
58 | @interface TTGTagCollectionView : UIView
59 | @property (nonatomic, weak) id dataSource;
60 | @property (nonatomic, weak) id delegate;
61 |
62 | // Inside scrollView
63 | @property (nonatomic, strong, readonly) UIScrollView *scrollView;
64 |
65 | // Tags scroll direction, default is vertical.
66 | @property (nonatomic, assign) TTGTagCollectionScrollDirection scrollDirection;
67 |
68 | // Tags layout alignment, default is left.
69 | @property (nonatomic, assign) TTGTagCollectionAlignment alignment;
70 |
71 | // Number of lines. 0 means no limit, default is 0 for vertical and 1 for horizontal.
72 | @property (nonatomic, assign) NSUInteger numberOfLines;
73 | // The real number of lines ignoring the numberOfLines value
74 | @property (nonatomic, assign, readonly) NSUInteger actualNumberOfLines;
75 |
76 | // Horizontal and vertical space between tags, default is 4.
77 | @property (nonatomic, assign) CGFloat horizontalSpacing;
78 | @property (nonatomic, assign) CGFloat verticalSpacing;
79 |
80 | // Content inset, default is UIEdgeInsetsMake(2, 2, 2, 2).
81 | @property (nonatomic, assign) UIEdgeInsets contentInset;
82 |
83 | // The true tags content size, readonly
84 | @property (nonatomic, assign, readonly) CGSize contentSize;
85 |
86 | // Manual content height
87 | // Default = NO, set will update content
88 | @property (nonatomic, assign) BOOL manualCalculateHeight;
89 | // Default = 0, set will update content
90 | @property (nonatomic, assign) CGFloat preferredMaxLayoutWidth;
91 |
92 | // Scroll indicator
93 | @property (nonatomic, assign) BOOL showsHorizontalScrollIndicator;
94 | @property (nonatomic, assign) BOOL showsVerticalScrollIndicator;
95 |
96 | // Tap blank area callback
97 | @property (nonatomic, copy) void (^onTapBlankArea)(CGPoint location);
98 | // Tap all area callback
99 | @property (nonatomic, copy) void (^onTapAllArea)(CGPoint location);
100 |
101 | /**
102 | * Reload all tag cells
103 | */
104 | - (void)reload;
105 |
106 | /**
107 | * Returns the index of the tag located at the specified point.
108 | * If item at point is not found, returns NSNotFound.
109 | */
110 | - (NSInteger)indexOfTagAt:(CGPoint)point;
111 |
112 | @end
113 |
--------------------------------------------------------------------------------
/Sources/TTGTagCollectionView.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTagCollectionView.m
3 | // Pods
4 | //
5 | // Created by zekunyan on 15/12/26.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGTagCollectionView.h"
10 |
11 | @interface TTGTagCollectionView ()
12 | @property (nonatomic, strong) UIScrollView *scrollView;
13 | @property (nonatomic, strong) UIView *containerView;
14 | @property (nonatomic, assign) BOOL needsLayoutTagViews;
15 | @property (nonatomic, assign) NSUInteger actualNumberOfLines;
16 | @end
17 |
18 | @implementation TTGTagCollectionView
19 |
20 | #pragma mark - Init
21 |
22 | - (instancetype)initWithFrame:(CGRect)frame {
23 | self = [super initWithFrame:frame];
24 | if (self) {
25 | [self commonInit];
26 | }
27 |
28 | return self;
29 | }
30 |
31 | - (instancetype)initWithCoder:(NSCoder *)coder {
32 | self = [super initWithCoder:coder];
33 | if (self) {
34 | [self commonInit];
35 | }
36 |
37 | return self;
38 | }
39 |
40 | - (void)commonInit {
41 | if (_scrollView) {
42 | return;
43 | }
44 |
45 | _horizontalSpacing = 4;
46 | _verticalSpacing = 4;
47 | _contentInset = UIEdgeInsetsMake(2, 2, 2, 2);
48 |
49 | _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
50 | _scrollView.backgroundColor = [UIColor clearColor];
51 | _scrollView.userInteractionEnabled = YES;
52 | [self addSubview:_scrollView];
53 |
54 | _containerView = [[UIView alloc] initWithFrame:_scrollView.bounds];
55 | _containerView.backgroundColor = [UIColor clearColor];
56 | _containerView.userInteractionEnabled = YES;
57 | [_scrollView addSubview:_containerView];
58 |
59 | UITapGestureRecognizer *tapGesture = [UITapGestureRecognizer new];
60 | [tapGesture addTarget:self action:@selector(onTapGesture:)];
61 | [_containerView addGestureRecognizer:tapGesture];
62 |
63 | [self setNeedsLayoutTagViews];
64 | }
65 |
66 | #pragma mark - Public methods
67 |
68 | - (void)reload {
69 | if (![self isDelegateAndDataSourceValid]) {
70 | return;
71 | }
72 |
73 | // Remove all tag views
74 | [_containerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
75 |
76 | // Add tag view
77 | for (NSUInteger i = 0; i < [_dataSource numberOfTagsInTagCollectionView:self]; i++) {
78 | [_containerView addSubview:[_dataSource tagCollectionView:self tagViewForIndex:i]];
79 | }
80 |
81 | // Update tag view frame
82 | [self setNeedsLayoutTagViews];
83 | [self layoutTagViews];
84 | }
85 |
86 | - (NSInteger)indexOfTagAt:(CGPoint)point {
87 | // We expect the point to be a point wrt to the TTGTagCollectionView.
88 | // so convert this point first to a point wrt to the container view.
89 | CGPoint convertedPoint = [self convertPoint:point toView:_containerView];
90 | for (NSUInteger i = 0; i < [self.dataSource numberOfTagsInTagCollectionView:self]; i++) {
91 | UIView *tagView = [self.dataSource tagCollectionView:self tagViewForIndex:i];
92 | if (CGRectContainsPoint(tagView.frame, convertedPoint) && !tagView.isHidden) {
93 | return i;
94 | }
95 | }
96 | return NSNotFound;
97 | }
98 |
99 | #pragma mark - Gesture
100 |
101 | - (void)onTapGesture:(UITapGestureRecognizer *)tapGesture {
102 | CGPoint tapPointInCollectionView = [tapGesture locationInView:self];
103 |
104 | if (![self.dataSource respondsToSelector:@selector(numberOfTagsInTagCollectionView:)] ||
105 | ![self.dataSource respondsToSelector:@selector(tagCollectionView:tagViewForIndex:)] ||
106 | ![self.delegate respondsToSelector:@selector(tagCollectionView:didSelectTag:atIndex:)]) {
107 | if (_onTapBlankArea) {
108 | _onTapBlankArea(tapPointInCollectionView);
109 | }
110 | if (_onTapAllArea) {
111 | _onTapAllArea(tapPointInCollectionView);
112 | }
113 | return;
114 | }
115 |
116 | CGPoint tapPointInScrollView = [tapGesture locationInView:_containerView];
117 | BOOL hasLocatedToTag = NO;
118 |
119 | for (NSUInteger i = 0; i < [self.dataSource numberOfTagsInTagCollectionView:self]; i++) {
120 | UIView *tagView = [self.dataSource tagCollectionView:self tagViewForIndex:i];
121 | if (CGRectContainsPoint(tagView.frame, tapPointInScrollView) && !tagView.isHidden) {
122 | hasLocatedToTag = YES;
123 | if ([self.delegate respondsToSelector:@selector(tagCollectionView:shouldSelectTag:atIndex:)]) {
124 | if ([self.delegate tagCollectionView:self shouldSelectTag:tagView atIndex:i]) {
125 | [self.delegate tagCollectionView:self didSelectTag:tagView atIndex:i];
126 | }
127 | } else {
128 | [self.delegate tagCollectionView:self didSelectTag:tagView atIndex:i];
129 | }
130 | }
131 | }
132 |
133 | if (!hasLocatedToTag) {
134 | if (_onTapBlankArea) {
135 | _onTapBlankArea(tapPointInCollectionView);
136 | }
137 | }
138 | if (_onTapAllArea) {
139 | _onTapAllArea(tapPointInCollectionView);
140 | }
141 | }
142 |
143 | #pragma mark - Override
144 |
145 | - (void)layoutSubviews {
146 | [super layoutSubviews];
147 |
148 | if (!CGRectEqualToRect(_scrollView.frame, self.bounds)) {
149 | _scrollView.frame = self.bounds;
150 | [self setNeedsLayoutTagViews];
151 | [self layoutTagViews];
152 | _containerView.frame = (CGRect){CGPointZero, _scrollView.contentSize};
153 | }
154 | [self layoutTagViews];
155 | }
156 |
157 | - (CGSize)intrinsicContentSize {
158 | return _scrollView.contentSize;
159 | }
160 |
161 | - (CGSize)sizeThatFits:(CGSize)size {
162 | return self.contentSize;
163 | }
164 |
165 | #pragma mark - Layout
166 |
167 | - (void)layoutTagViews {
168 | if (!_needsLayoutTagViews || ![self isDelegateAndDataSourceValid]) {
169 | return;
170 | }
171 |
172 | if (_scrollDirection == TTGTagCollectionScrollDirectionVertical) {
173 | [self layoutTagViewsForVerticalDirection];
174 | } else {
175 | [self layoutTagViewsForHorizontalDirection];
176 | }
177 |
178 | _needsLayoutTagViews = NO;
179 | [self invalidateIntrinsicContentSize];
180 | }
181 |
182 | - (void)layoutTagViewsForVerticalDirection {
183 | NSUInteger count = [_dataSource numberOfTagsInTagCollectionView:self];
184 | NSUInteger currentLineTagsCount = 0;
185 | CGFloat totalWidth = (_manualCalculateHeight && _preferredMaxLayoutWidth > 0) ? _preferredMaxLayoutWidth : CGRectGetWidth(self.bounds);
186 | CGFloat maxLineWidth = totalWidth - _contentInset.left - _contentInset.right;
187 | CGFloat currentLineX = 0;
188 | CGFloat currentLineMaxHeight = 0;
189 |
190 | NSMutableArray *eachLineMaxHeightNumbers = [NSMutableArray new];
191 | NSMutableArray *eachLineWidthNumbers = [NSMutableArray new];
192 | NSMutableArray *eachLineTagCountNumbers = [NSMutableArray new];
193 |
194 | NSMutableArray *> *eachLineTagIndexs = [NSMutableArray new];
195 | NSMutableArray *tmpTagIndexNumbers = [NSMutableArray new];
196 |
197 | // Get each line max height ,width and tag count
198 | for (NSUInteger i = 0; i < count; i++) {
199 | CGSize tagSize = [_delegate tagCollectionView:self sizeForTagAtIndex:i];
200 |
201 | if (currentLineX + tagSize.width > maxLineWidth && tmpTagIndexNumbers.count > 0) {
202 | // New Line
203 | [eachLineMaxHeightNumbers addObject:@(currentLineMaxHeight)];
204 | [eachLineWidthNumbers addObject:@(currentLineX - _horizontalSpacing)];
205 | [eachLineTagCountNumbers addObject:@(currentLineTagsCount)];
206 | [eachLineTagIndexs addObject:tmpTagIndexNumbers];
207 | tmpTagIndexNumbers = [NSMutableArray new];
208 | currentLineTagsCount = 0;
209 | currentLineMaxHeight = 0;
210 | currentLineX = 0;
211 | }
212 |
213 | // Line limit
214 | if (_numberOfLines != 0) {
215 | UIView *tagView = [_dataSource tagCollectionView:self tagViewForIndex:i];
216 | tagView.hidden = eachLineWidthNumbers.count >= _numberOfLines;
217 | }
218 |
219 | currentLineX += tagSize.width + _horizontalSpacing;
220 | currentLineTagsCount += 1;
221 | currentLineMaxHeight = MAX(tagSize.height, currentLineMaxHeight);
222 | [tmpTagIndexNumbers addObject:@(i)];
223 | }
224 |
225 | // Add last
226 | [eachLineMaxHeightNumbers addObject:@(currentLineMaxHeight)];
227 | [eachLineWidthNumbers addObject:@(currentLineX - _horizontalSpacing)];
228 | [eachLineTagCountNumbers addObject:@(currentLineTagsCount)];
229 | [eachLineTagIndexs addObject:tmpTagIndexNumbers];
230 |
231 | // Actual number of lines
232 | _actualNumberOfLines = eachLineTagCountNumbers.count;
233 |
234 | // Line limit
235 | if (_numberOfLines != 0) {
236 | eachLineMaxHeightNumbers = [[eachLineMaxHeightNumbers subarrayWithRange:NSMakeRange(0, MIN(eachLineMaxHeightNumbers.count, _numberOfLines))] mutableCopy];
237 | eachLineWidthNumbers = [[eachLineWidthNumbers subarrayWithRange:NSMakeRange(0, MIN(eachLineWidthNumbers.count, _numberOfLines))] mutableCopy];
238 | eachLineTagCountNumbers = [[eachLineTagCountNumbers subarrayWithRange:NSMakeRange(0, MIN(eachLineTagCountNumbers.count, _numberOfLines))] mutableCopy];
239 | eachLineTagIndexs = [[eachLineTagIndexs subarrayWithRange:NSMakeRange(0, MIN(eachLineTagIndexs.count, _numberOfLines))] mutableCopy];
240 | }
241 |
242 | // Prepare
243 | [self layoutEachLineTagsWithMaxLineWidth:maxLineWidth
244 | numberOfLines:eachLineTagCountNumbers.count
245 | eachLineTagIndexs:eachLineTagIndexs
246 | eachLineTagCount:eachLineTagCountNumbers
247 | eachLineWidth:eachLineWidthNumbers
248 | eachLineMaxHeight:eachLineMaxHeightNumbers];
249 | }
250 |
251 | - (void)layoutTagViewsForHorizontalDirection {
252 | NSInteger count = [_dataSource numberOfTagsInTagCollectionView:self];
253 | _numberOfLines = _numberOfLines == 0 ? 1 : _numberOfLines;
254 |
255 | CGFloat maxLineWidth = 0;
256 |
257 | NSMutableArray *eachLineMaxHeightNumbers = [NSMutableArray new];
258 | NSMutableArray *eachLineWidthNumbers = [NSMutableArray new];
259 | NSMutableArray *eachLineTagCountNumbers = [NSMutableArray new];
260 |
261 | NSMutableArray *> *eachLineTagIndexs = [NSMutableArray new];
262 |
263 | // Init each line
264 | for (NSInteger currentLine = 0; currentLine < _numberOfLines; currentLine++) {
265 | [eachLineMaxHeightNumbers addObject:@0];
266 | [eachLineWidthNumbers addObject:@0];
267 | [eachLineTagCountNumbers addObject:@0];
268 | [eachLineTagIndexs addObject:[NSMutableArray new]];
269 | }
270 |
271 | // Add tags
272 | for (NSUInteger tagIndex = 0; tagIndex < count; tagIndex++) {
273 | NSUInteger currentLine = tagIndex % _numberOfLines;
274 |
275 | NSUInteger currentLineTagsCount = eachLineTagCountNumbers[currentLine].unsignedIntegerValue;
276 | CGFloat currentLineMaxHeight = eachLineMaxHeightNumbers[currentLine].floatValue;
277 | CGFloat currentLineX = eachLineWidthNumbers[currentLine].floatValue;
278 | NSMutableArray *currentLineTagIndexNumbers = eachLineTagIndexs[currentLine];
279 |
280 | CGSize tagSize = [_delegate tagCollectionView:self sizeForTagAtIndex:tagIndex];
281 | currentLineX += tagSize.width + _horizontalSpacing;
282 | currentLineMaxHeight = MAX(tagSize.height, currentLineMaxHeight);
283 | currentLineTagsCount += 1;
284 | [currentLineTagIndexNumbers addObject:@(tagIndex)];
285 |
286 | eachLineTagCountNumbers[currentLine] = @(currentLineTagsCount);
287 | eachLineMaxHeightNumbers[currentLine] = @(currentLineMaxHeight);
288 | eachLineWidthNumbers[currentLine] = @(currentLineX);
289 | eachLineTagIndexs[currentLine] = currentLineTagIndexNumbers;
290 | }
291 |
292 | // Remove extra space
293 | for (NSInteger currentLine = 0; currentLine < _numberOfLines; currentLine++) {
294 | CGFloat currentLineWidth = eachLineWidthNumbers[currentLine].floatValue;
295 | currentLineWidth -= _horizontalSpacing;
296 | eachLineWidthNumbers[currentLine] = @(currentLineWidth);
297 |
298 | maxLineWidth = MAX(currentLineWidth, maxLineWidth);
299 | }
300 |
301 | // Prepare
302 | [self layoutEachLineTagsWithMaxLineWidth:maxLineWidth
303 | numberOfLines:eachLineTagCountNumbers.count
304 | eachLineTagIndexs:eachLineTagIndexs
305 | eachLineTagCount:eachLineTagCountNumbers
306 | eachLineWidth:eachLineWidthNumbers
307 | eachLineMaxHeight:eachLineMaxHeightNumbers];
308 | }
309 |
310 | - (void)layoutEachLineTagsWithMaxLineWidth:(CGFloat)maxLineWidth
311 | numberOfLines:(NSUInteger)numberOfLines
312 | eachLineTagIndexs:(NSArray *> *)eachLineTagIndexs
313 | eachLineTagCount:(NSArray *)eachLineTagCount
314 | eachLineWidth:(NSArray *)eachLineWidth
315 | eachLineMaxHeight:(NSArray *)eachLineMaxHeight {
316 |
317 | CGFloat currentYBase = _contentInset.top;
318 |
319 | for (NSUInteger currentLine = 0; currentLine < numberOfLines; currentLine++) {
320 | CGFloat currentLineMaxHeight = eachLineMaxHeight[currentLine].floatValue;
321 | CGFloat currentLineWidth = eachLineWidth[currentLine].floatValue;
322 | CGFloat currentLineTagsCount = eachLineTagCount[currentLine].unsignedIntegerValue;
323 |
324 | // Alignment x offset
325 | CGFloat currentLineXOffset = 0;
326 | CGFloat currentLineAdditionWidth = 0;
327 | CGFloat acturalHorizontalSpacing = _horizontalSpacing;
328 | __block CGFloat currentLineX = 0;
329 |
330 | switch (_alignment) {
331 | case TTGTagCollectionAlignmentLeft:
332 | currentLineXOffset = _contentInset.left;
333 | break;
334 | case TTGTagCollectionAlignmentCenter:
335 | currentLineXOffset = (maxLineWidth - currentLineWidth) / 2 + _contentInset.left;
336 | break;
337 | case TTGTagCollectionAlignmentRight:
338 | currentLineXOffset = maxLineWidth - currentLineWidth + _contentInset.left;
339 | break;
340 | case TTGTagCollectionAlignmentFillByExpandingSpace:
341 | currentLineXOffset = _contentInset.left;
342 | acturalHorizontalSpacing = _horizontalSpacing +
343 | (maxLineWidth - currentLineWidth) / (CGFloat)(currentLineTagsCount - 1);
344 | currentLineWidth = maxLineWidth;
345 | break;
346 | case TTGTagCollectionAlignmentFillByExpandingWidth:
347 | case TTGTagCollectionAlignmentFillByExpandingWidthExceptLastLine:
348 | currentLineXOffset = _contentInset.left;
349 | currentLineAdditionWidth = (maxLineWidth - currentLineWidth) / (CGFloat)currentLineTagsCount;
350 | currentLineWidth = maxLineWidth;
351 |
352 | if (_alignment == TTGTagCollectionAlignmentFillByExpandingWidthExceptLastLine &&
353 | currentLine == numberOfLines - 1 &&
354 | numberOfLines != 1) {
355 | // Reset last line width for TTGTagCollectionAlignmentFillByExpandingWidthExceptLastLine
356 | currentLineAdditionWidth = 0;
357 | }
358 |
359 | break;
360 | }
361 |
362 | // Current line
363 | [eachLineTagIndexs[currentLine] enumerateObjectsUsingBlock:^(NSNumber * _Nonnull tagIndexNumber, NSUInteger idx, BOOL * _Nonnull stop) {
364 | NSUInteger tagIndex = tagIndexNumber.unsignedIntegerValue;
365 |
366 | UIView *tagView = [self.dataSource tagCollectionView:self tagViewForIndex:tagIndex];
367 | CGSize tagSize = [self.delegate tagCollectionView:self sizeForTagAtIndex:tagIndex];
368 |
369 | CGPoint origin;
370 | origin.x = currentLineXOffset + currentLineX;
371 | origin.y = currentYBase + (currentLineMaxHeight - tagSize.height) / 2;
372 |
373 | tagSize.width += currentLineAdditionWidth;
374 | if (self.scrollDirection == TTGTagCollectionScrollDirectionVertical && tagSize.width > maxLineWidth) {
375 | tagSize.width = maxLineWidth;
376 | }
377 |
378 | tagView.hidden = NO;
379 | tagView.frame = (CGRect){origin, tagSize};
380 |
381 | currentLineX += tagSize.width + acturalHorizontalSpacing;
382 | }];
383 |
384 | // Next line
385 | currentYBase += currentLineMaxHeight + _verticalSpacing;
386 | }
387 |
388 | // Content size
389 | maxLineWidth += _contentInset.right + _contentInset.left;
390 | CGSize contentSize = CGSizeMake(maxLineWidth, currentYBase - _verticalSpacing + _contentInset.bottom);
391 | if (!CGSizeEqualToSize(contentSize, _scrollView.contentSize)) {
392 | _scrollView.contentSize = contentSize;
393 | _containerView.frame = (CGRect){CGPointZero, contentSize};
394 |
395 | if ([self.delegate respondsToSelector:@selector(tagCollectionView:updateContentSize:)]) {
396 | [self.delegate tagCollectionView:self updateContentSize:contentSize];
397 | }
398 | }
399 | }
400 |
401 | - (void)setNeedsLayoutTagViews {
402 | _needsLayoutTagViews = YES;
403 | }
404 |
405 | #pragma mark - Check delegate and dataSource
406 |
407 | - (BOOL)isDelegateAndDataSourceValid {
408 | BOOL isValid = _delegate != nil && _dataSource != nil;
409 | isValid = isValid && [_delegate respondsToSelector:@selector(tagCollectionView:sizeForTagAtIndex:)];
410 | isValid = isValid && [_dataSource respondsToSelector:@selector(tagCollectionView:tagViewForIndex:)];
411 | isValid = isValid && [_dataSource respondsToSelector:@selector(numberOfTagsInTagCollectionView:)];
412 | return isValid;
413 | }
414 |
415 | #pragma mark - Setter Getter
416 |
417 | - (UIScrollView *)scrollView {
418 | return _scrollView;
419 | }
420 |
421 | - (void)setScrollDirection:(TTGTagCollectionScrollDirection)scrollDirection {
422 | _scrollDirection = scrollDirection;
423 | [self setNeedsLayoutTagViews];
424 | }
425 |
426 | - (void)setAlignment:(TTGTagCollectionAlignment)alignment {
427 | _alignment = alignment;
428 | [self setNeedsLayoutTagViews];
429 | }
430 |
431 | - (void)setNumberOfLines:(NSUInteger)numberOfLines {
432 | _numberOfLines = numberOfLines;
433 | [self setNeedsLayoutTagViews];
434 | }
435 |
436 | - (NSUInteger)actualNumberOfLines {
437 | if (_scrollDirection == TTGTagCollectionScrollDirectionHorizontal) {
438 | return _numberOfLines;
439 | } else {
440 | return _actualNumberOfLines;
441 | }
442 | }
443 |
444 | - (void)setHorizontalSpacing:(CGFloat)horizontalSpacing {
445 | _horizontalSpacing = horizontalSpacing;
446 | [self setNeedsLayoutTagViews];
447 | }
448 |
449 | - (void)setVerticalSpacing:(CGFloat)verticalSpacing {
450 | _verticalSpacing = verticalSpacing;
451 | [self setNeedsLayoutTagViews];
452 | }
453 |
454 | - (void)setContentInset:(UIEdgeInsets)contentInset {
455 | _contentInset = contentInset;
456 | [self setNeedsLayoutTagViews];
457 | }
458 |
459 | - (CGSize)contentSize {
460 | [self layoutTagViews];
461 | return _scrollView.contentSize;
462 | }
463 |
464 | - (void)setManualCalculateHeight:(BOOL)manualCalculateHeight {
465 | _manualCalculateHeight = manualCalculateHeight;
466 | [self setNeedsLayoutTagViews];
467 | }
468 |
469 | - (void)setPreferredMaxLayoutWidth:(CGFloat)preferredMaxLayoutWidth {
470 | _preferredMaxLayoutWidth = preferredMaxLayoutWidth;
471 | [self setNeedsLayoutTagViews];
472 | }
473 |
474 | - (void)setShowsHorizontalScrollIndicator:(BOOL)showsHorizontalScrollIndicator {
475 | _scrollView.showsHorizontalScrollIndicator = showsHorizontalScrollIndicator;
476 | }
477 |
478 | - (BOOL)showsHorizontalScrollIndicator {
479 | return _scrollView.showsHorizontalScrollIndicator;
480 | }
481 |
482 | - (void)setShowsVerticalScrollIndicator:(BOOL)showsVerticalScrollIndicator {
483 | _scrollView.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
484 | }
485 |
486 | - (BOOL)showsVerticalScrollIndicator {
487 | return _scrollView.showsVerticalScrollIndicator;
488 | }
489 |
490 | @end
491 |
--------------------------------------------------------------------------------
/Sources/TTGTextTag.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTag.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #import "TTGTextTagStyle.h"
13 | #import "TTGTextTagContent.h"
14 |
15 | /// Tag selection state change callback
16 | typedef void (^OnSelectStateChanged)(bool selected);
17 |
18 | @interface TTGTextTag : NSObject
19 |
20 | /// ID
21 | @property (nonatomic, assign, readonly) NSUInteger tagId; // Auto increase. The only identifier and main key for a tag
22 |
23 | /// Attachment object. You can use this to bind any object you want to each tag.
24 | @property (nonatomic, strong) id _Nullable attachment;
25 |
26 | /// Normal state content and style
27 | @property (nonatomic, copy) TTGTextTagContent * _Nonnull content;
28 | @property (nonatomic, copy) TTGTextTagStyle * _Nonnull style;
29 |
30 | /// Selected state content and style
31 | @property (nonatomic, copy) TTGTextTagContent * _Nullable selectedContent;
32 | @property (nonatomic, copy) TTGTextTagStyle * _Nullable selectedStyle;
33 |
34 | /// Selection state
35 | @property (nonatomic, assign) BOOL selected;
36 | @property (nonatomic, copy) OnSelectStateChanged _Nullable onSelectStateChanged; // State changed callback
37 |
38 | /// Accessibility
39 | @property (nonatomic, assign) BOOL isAccessibilityElement; // Default = NO
40 | @property (nonatomic, copy) NSString * _Nullable accessibilityIdentifier; // Default = nil
41 | @property (nonatomic, copy) NSString * _Nullable accessibilityLabel; // Default = nil
42 | @property (nonatomic, copy) NSString * _Nullable accessibilityHint; // Default = nil
43 | @property (nonatomic, copy) NSString * _Nullable accessibilityValue; // Default = nil
44 | @property (nonatomic, assign) UIAccessibilityTraits accessibilityTraits; // Default = UIAccessibilityTraitNone
45 |
46 | /// Auto detect accessibility
47 | /// When enableAutoDetectAccessibility = YES, the property below will be set automatically
48 | /// ----------------------------
49 | /// isAccessibilityElement = YES
50 | /// accessibilityLabel = (selected ? selectedContent : content).getContentAttributedString.string
51 | /// accessibilityTraits = selected ? UIAccessibilityTraitSelected : UIAccessibilityTraitButton
52 | /// ----------------------------
53 | /// But: accessibilityHint and accessibilityValue still keep your custom value;
54 | @property (nonatomic, assign) BOOL enableAutoDetectAccessibility; // Default = NO
55 |
56 | /// Init
57 |
58 | /**
59 | Init with single content and style
60 |
61 | @param content content for both normal and selection state.
62 | @param style style for both normal and selection state.
63 | @return instance
64 | */
65 | - (instancetype _Nonnull)initWithContent:(TTGTextTagContent *_Nonnull)content
66 | style:(TTGTextTagStyle *_Nonnull)style;
67 |
68 | /**
69 | Init with different content and style
70 |
71 | @param content content for normal state
72 | @param style style for normal state
73 | @param selectedContent content for selection state
74 | @param selectedStyle style for selection state
75 | @return instance
76 | */
77 | - (instancetype _Nonnull)initWithContent:(TTGTextTagContent *_Nonnull)content
78 | style:(TTGTextTagStyle *_Nonnull)style
79 | selectedContent:(TTGTextTagContent *_Nullable)selectedContent
80 | selectedStyle:(TTGTextTagStyle *_Nullable)selectedStyle;
81 |
82 | /**
83 | Tag with single content and style
84 |
85 | @param content content for both normal and selection state.
86 | @param style style for both normal and selection state.
87 | @return instance
88 | */
89 | + (instancetype _Nonnull)tagWithContent:(TTGTextTagContent *_Nonnull)content
90 | style:(TTGTextTagStyle *_Nonnull)style;
91 |
92 | /**
93 | Tag with different content and style
94 |
95 | @param content content for normal state
96 | @param style style for normal state
97 | @param selectedContent content for selection state
98 | @param selectedStyle style for selection state
99 | @return instance
100 | */
101 | + (instancetype _Nonnull)tagWithContent:(TTGTextTagContent *_Nonnull)content
102 | style:(TTGTextTagStyle *_Nonnull)style
103 | selectedContent:(TTGTextTagContent *_Nullable)selectedContent
104 | selectedStyle:(TTGTextTagStyle *_Nullable)selectedStyle;
105 |
106 | /**
107 | Get current state rightful content
108 |
109 | @return content
110 | */
111 | - (TTGTextTagContent *_Nonnull)getRightfulContent;
112 |
113 | /**
114 | Get current state rightful style
115 |
116 | @return style
117 | */
118 | - (TTGTextTagStyle *_Nonnull)getRightfulStyle;
119 |
120 | /// Base system methods
121 | - (BOOL)isEqual:(id _Nullable)other;
122 | - (BOOL)isEqualToTag:(TTGTextTag *_Nullable)tag;
123 | - (NSUInteger)hash;
124 |
125 | /// Copy
126 | - (id _Nonnull)copyWithZone:(NSZone *_Nullable)zone;
127 |
128 | @end
129 |
--------------------------------------------------------------------------------
/Sources/TTGTextTag.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTag.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGTextTag.h"
10 | #import "TTGTextTagStringContent.h"
11 |
12 | static NSUInteger TTGTextTagAutoIncreasedId = 0;
13 |
14 | @implementation TTGTextTag
15 |
16 | - (instancetype)initWithContent:(TTGTextTagContent *)content
17 | style:(TTGTextTagStyle *)style {
18 | self = [self init];
19 | if (self) {
20 | self.content = content;
21 | self.style = style;
22 | }
23 | return self;
24 | }
25 |
26 | - (instancetype)initWithContent:(TTGTextTagContent *)content
27 | style:(TTGTextTagStyle *)style
28 | selectedContent:(TTGTextTagContent *)selectedContent
29 | selectedStyle:(TTGTextTagStyle *)selectedStyle {
30 | self = [self init];
31 | if (self) {
32 | self.content = content;
33 | self.style = style;
34 | self.selectedContent = selectedContent;
35 | self.selectedStyle = selectedStyle;
36 | }
37 | return self;
38 | }
39 |
40 | + (instancetype)tagWithContent:(TTGTextTagContent *)content
41 | style:(TTGTextTagStyle *)style {
42 | return [[self alloc] initWithContent:content style:style];
43 | }
44 |
45 | + (instancetype)tagWithContent:(TTGTextTagContent *)content
46 | style:(TTGTextTagStyle *)style
47 | selectedContent:(TTGTextTagContent *)selectedContent
48 | selectedStyle:(TTGTextTagStyle *)selectedStyle {
49 | return [[self alloc] initWithContent:content
50 | style:style
51 | selectedContent:selectedContent
52 | selectedStyle:selectedStyle];
53 | }
54 |
55 | - (instancetype)init {
56 | self = [super init];
57 | if (self) {
58 | _tagId = TTGTextTagAutoIncreasedId++;
59 | _attachment = nil;
60 | }
61 | return self;
62 | }
63 |
64 | - (void)setSelected:(BOOL)selected {
65 | _selected = selected;
66 | // Callback
67 | if (_onSelectStateChanged) {
68 | _onSelectStateChanged(selected);
69 | }
70 | }
71 |
72 | - (TTGTextTagContent *)selectedContent {
73 | if (_selectedContent == nil) {
74 | _selectedContent = [_content copy];
75 | }
76 | return _selectedContent;
77 | }
78 |
79 | - (TTGTextTagStyle *)selectedStyle {
80 | if (_selectedStyle == nil) {
81 | _selectedStyle = [_style copy];
82 | }
83 | return _selectedStyle;
84 | }
85 |
86 | - (TTGTextTagContent *)getRightfulContent {
87 | return _selected ? self.selectedContent : self.content;
88 | }
89 |
90 | - (TTGTextTagStyle *)getRightfulStyle {
91 | return _selected ? self.selectedStyle : self.style;
92 | }
93 |
94 | - (BOOL)isAccessibilityElement {
95 | return _enableAutoDetectAccessibility || _isAccessibilityElement;
96 | }
97 |
98 | - (NSString *)accessibilityLabel {
99 | if (_enableAutoDetectAccessibility) {
100 | return [self getRightfulContent].getContentAttributedString.string;
101 | }
102 | return _accessibilityLabel;
103 | }
104 |
105 | - (UIAccessibilityTraits)accessibilityTraits {
106 | if (_enableAutoDetectAccessibility) {
107 | return _selected ? UIAccessibilityTraitSelected : UIAccessibilityTraitButton;
108 | }
109 | return _accessibilityTraits;
110 | }
111 |
112 | - (BOOL)isEqual:(id)other {
113 | if (other == self)
114 | return YES;
115 | if (!other || ![[other class] isEqual:[self class]])
116 | return NO;
117 |
118 | return [self isEqualToTag:other];
119 | }
120 |
121 | - (BOOL)isEqualToTag:(TTGTextTag *)tag {
122 | if (self == tag)
123 | return YES;
124 | if (tag == nil)
125 | return NO;
126 | if (self.tagId != tag.tagId)
127 | return NO;
128 | return YES;
129 | }
130 |
131 | - (NSUInteger)hash {
132 | return (NSUInteger)self.tagId;
133 | }
134 |
135 | - (id)copyWithZone:(nullable NSZone *)zone {
136 | TTGTextTag *copy = (TTGTextTag *)[[[self class] allocWithZone:zone] init];
137 | if (copy != nil) {
138 | copy->_tagId = TTGTextTagAutoIncreasedId++;
139 | copy.attachment = self.attachment;
140 | copy.content = self.content;
141 | copy.style = self.style;
142 | copy.selected = self.selected;
143 | copy.selectedContent = self.selectedContent;
144 | copy.selectedStyle = self.selectedStyle;
145 | copy.isAccessibilityElement = self.isAccessibilityElement;
146 | copy.accessibilityLabel = self.accessibilityLabel;
147 | copy.accessibilityHint = self.accessibilityHint;
148 | copy.accessibilityValue = self.accessibilityValue;
149 | copy.accessibilityTraits = self.accessibilityTraits;
150 | copy.enableAutoDetectAccessibility = self.enableAutoDetectAccessibility;
151 | }
152 | return copy;
153 | }
154 |
155 | @end
156 |
--------------------------------------------------------------------------------
/Sources/TTGTextTagAttributedStringContent.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTagAttributedStringContent.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGTextTagContent.h"
10 |
11 | /**
12 | Rich text content for tag
13 | */
14 | @interface TTGTextTagAttributedStringContent : TTGTextTagContent
15 |
16 | /// Attributed text
17 | @property (nonatomic, copy) NSAttributedString * _Nonnull attributedText;
18 |
19 | /// Init with rich text
20 | - (instancetype _Nonnull)initWithAttributedText:(NSAttributedString *_Nonnull)attributedText;
21 |
22 | /// Content with rich text
23 | + (instancetype _Nonnull)contentWithAttributedText:(NSAttributedString *_Nonnull)attributedText;
24 |
25 | /// Base system methods
26 | - (id _Nonnull)copyWithZone:(NSZone *_Nullable)zone;
27 | - (NSString *_Nonnull)description;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/Sources/TTGTextTagAttributedStringContent.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTagAttributedStringContent.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGTextTagAttributedStringContent.h"
10 |
11 | @implementation TTGTextTagAttributedStringContent
12 |
13 | - (instancetype)initWithAttributedText:(NSAttributedString *)attributedText {
14 | self = [super init];
15 | if (self) {
16 | self.attributedText = attributedText;
17 | }
18 | return self;
19 | }
20 |
21 | + (instancetype)contentWithAttributedText:(NSAttributedString *)attributedText {
22 | return [[self alloc] initWithAttributedText:attributedText];
23 | }
24 |
25 | - (NSAttributedString *)getContentAttributedString {
26 | return self.attributedText;
27 | }
28 |
29 | - (NSAttributedString *)attributedText {
30 | return _attributedText ?: [NSAttributedString new];
31 | }
32 |
33 | - (id)copyWithZone:(NSZone *)zone {
34 | TTGTextTagAttributedStringContent *copy = (TTGTextTagAttributedStringContent *)[super copyWithZone:zone];
35 | if (copy != nil) {
36 | copy.attributedText = self.attributedText;
37 | }
38 | return copy;
39 | }
40 |
41 | - (NSString *)description {
42 | NSMutableString *description = [NSMutableString stringWithFormat:@"<%@: ", NSStringFromClass([self class])];
43 | [description appendFormat:@"self.attributedText=%@", self.attributedText];
44 | [description appendString:@">"];
45 | return description;
46 | }
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/Sources/TTGTextTagCollectionView.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTagCollectionView.h
3 | // Pods
4 | //
5 | // Created by zekunyan on 15/12/26.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "TTGTagCollectionView.h"
12 | #import "TTGTextTag.h"
13 | #import "TTGTextTagStringContent.h"
14 | #import "TTGTextTagAttributedStringContent.h"
15 |
16 | /**
17 | Highly useful for text tag display.
18 | */
19 |
20 | @class TTGTextTagCollectionView;
21 |
22 | /// Delegate
23 | @protocol TTGTextTagCollectionViewDelegate
24 | @optional
25 |
26 | - (BOOL)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView
27 | canTapTag:(TTGTextTag *)tag
28 | atIndex:(NSUInteger)index;
29 |
30 | - (void)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView
31 | didTapTag:(TTGTextTag *)tag
32 | atIndex:(NSUInteger)index;
33 |
34 | - (void)textTagCollectionView:(TTGTextTagCollectionView *)textTagCollectionView
35 | updateContentSize:(CGSize)contentSize;
36 | @end
37 |
38 | /// Main Class
39 | @interface TTGTextTagCollectionView : UIView
40 | /// Delegate
41 | @property (weak, nonatomic) id delegate;
42 |
43 | /// Inside scrollView
44 | @property (nonatomic, strong, readonly) UIScrollView *scrollView;
45 |
46 | /// Define if the tag can be selected.
47 | @property (assign, nonatomic) BOOL enableTagSelection;
48 |
49 | /// Tags scroll direction, default is vertical.
50 | @property (nonatomic, assign) TTGTagCollectionScrollDirection scrollDirection;
51 |
52 | /// Tags layout alignment, default is left.
53 | @property (nonatomic, assign) TTGTagCollectionAlignment alignment;
54 |
55 | /// Number of lines. 0 means no limit, default is 0 for vertical and 1 for horizontal.
56 | @property (nonatomic, assign) NSUInteger numberOfLines;
57 | /// The real number of lines ignoring the numberOfLines value
58 | @property (nonatomic, assign, readonly) NSUInteger actualNumberOfLines;
59 |
60 | /// Tag selection limit, default is 0, means no limit
61 | @property (nonatomic, assign) NSUInteger selectionLimit;
62 |
63 | /// Horizontal and vertical space between tags, default is 4.
64 | @property (assign, nonatomic) CGFloat horizontalSpacing;
65 | @property (assign, nonatomic) CGFloat verticalSpacing;
66 |
67 | /// Content inset, like padding, default is UIEdgeInsetsMake(2, 2, 2, 2).
68 | @property (nonatomic, assign) UIEdgeInsets contentInset;
69 |
70 | /// The true tags content size, readonly
71 | @property (nonatomic, assign, readonly) CGSize contentSize;
72 |
73 | /// Manual content height
74 | /// Default = NO, set will update content
75 | @property (nonatomic, assign) BOOL manualCalculateHeight;
76 | /// Default = 0, set will update content
77 | @property (nonatomic, assign) CGFloat preferredMaxLayoutWidth;
78 |
79 | /// Scroll indicator
80 | @property (nonatomic, assign) BOOL showsHorizontalScrollIndicator;
81 | @property (nonatomic, assign) BOOL showsVerticalScrollIndicator;
82 |
83 | /// Tap blank area callback
84 | @property (nonatomic, copy) void (^onTapBlankArea)(CGPoint location);
85 | /// Tap all area callback
86 | @property (nonatomic, copy) void (^onTapAllArea)(CGPoint location);
87 |
88 | /// Reload
89 | - (void)reload;
90 |
91 | /// Add
92 | - (void)addTag:(TTGTextTag *)tag;
93 | - (void)addTags:(NSArray *)tags;
94 |
95 | /// Insert
96 | - (void)insertTag:(TTGTextTag *)tag atIndex:(NSUInteger)index;
97 | - (void)insertTags:(NSArray *)tags atIndex:(NSUInteger)index;
98 |
99 | /// Update
100 | - (void)updateTagAtIndex:(NSUInteger)index selected:(BOOL)selected;
101 | - (void)updateTagAtIndex:(NSUInteger)index withNewTag:(TTGTextTag *)tag;
102 |
103 | /// Remove
104 | - (void)removeTag:(TTGTextTag *)tag;
105 | - (void)removeTagById:(NSUInteger)tagId;
106 | - (void)removeTagAtIndex:(NSUInteger)index;
107 | - (void)removeAllTags;
108 |
109 | /// Get tag
110 | - (TTGTextTag *)getTagAtIndex:(NSUInteger)index;
111 | - (NSArray *)getTagsInRange:(NSRange)range;
112 |
113 | /// Get all
114 | - (NSArray *)allTags;
115 | - (NSArray *)allSelectedTags;
116 | - (NSArray *)allNotSelectedTags;
117 |
118 | /**
119 | * Returns the index of the tag located at the specified point.
120 | * If item at point is not found, returns NSNotFound.
121 | */
122 | - (NSInteger)indexOfTagAtPoint:(CGPoint)point;
123 |
124 | @end
125 |
--------------------------------------------------------------------------------
/Sources/TTGTextTagContent.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTagContent.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | Base content class.
13 | Do not use this class directly!
14 | */
15 | @interface TTGTextTagContent : NSObject
16 |
17 | /// Must be override by subClass
18 | - (NSAttributedString *_Nonnull)getContentAttributedString;
19 |
20 | /// Must be override by subClass
21 | - (id _Nonnull)copyWithZone:(NSZone *_Nullable)zone;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/Sources/TTGTextTagContent.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTagContent.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGTextTagContent.h"
10 |
11 | @implementation TTGTextTagContent
12 |
13 | - (NSAttributedString *)getContentAttributedString {
14 | NSAssert(NO, @"Do not use TTGTextTagContent directly.");
15 | return [NSAttributedString new];
16 | }
17 |
18 | - (id)copyWithZone:(NSZone *)zone {
19 | return [[[self class] allocWithZone:zone] init];
20 | }
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/Sources/TTGTextTagStringContent.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTagStringContent.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGTextTagContent.h"
10 |
11 | /**
12 | Normal text content with custom font and color.
13 | */
14 | @interface TTGTextTagStringContent : TTGTextTagContent
15 |
16 | /// Text
17 | @property (nonatomic, copy) NSString * _Nonnull text;
18 | /// Text font
19 | @property (nonatomic, copy) UIFont * _Nonnull textFont;
20 | /// Text color
21 | @property (nonatomic, copy) UIColor * _Nonnull textColor;
22 |
23 | /// Init
24 | - (instancetype _Nonnull)initWithText:(NSString *_Nonnull)text;
25 | - (instancetype _Nonnull)initWithText:(NSString *_Nonnull)text
26 | textFont:(UIFont *_Nullable)textFont
27 | textColor:(UIColor *_Nullable)textColor;
28 |
29 | /// Content
30 | + (instancetype _Nonnull)contentWithText:(NSString *_Nonnull)text;
31 | + (instancetype _Nonnull)contentWithText:(NSString *_Nonnull)text
32 | textFont:(UIFont *_Nullable)textFont
33 | textColor:(UIColor *_Nullable)textColor;
34 |
35 | /// Base system methods
36 | - (id _Nonnull)copyWithZone:(NSZone *_Nullable)zone;
37 | - (NSString *_Nonnull)description;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/Sources/TTGTextTagStringContent.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTagStringContent.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGTextTagStringContent.h"
10 |
11 | @implementation TTGTextTagStringContent
12 |
13 | - (instancetype)initWithText:(NSString *)text {
14 | self = [super init];
15 | if (self) {
16 | self.text = text;
17 | }
18 | return self;
19 | }
20 |
21 | + (instancetype)contentWithText:(NSString *)text {
22 | return [[self alloc] initWithText:text];
23 | }
24 |
25 | - (instancetype)initWithText:(NSString *)text
26 | textFont:(UIFont *)textFont
27 | textColor:(UIColor *)textColor {
28 | self = [super init];
29 | if (self) {
30 | self.text = text;
31 | self.textFont = textFont;
32 | self.textColor = textColor;
33 | }
34 | return self;
35 | }
36 |
37 | + (instancetype)contentWithText:(NSString *)text
38 | textFont:(UIFont *)textFont
39 | textColor:(UIColor *)textColor {
40 | return [[self alloc] initWithText:text
41 | textFont:textFont
42 | textColor:textColor];
43 | }
44 |
45 | - (NSAttributedString *)getContentAttributedString {
46 | return [[NSAttributedString alloc] initWithString:self.text
47 | attributes:@{NSForegroundColorAttributeName: self.textColor,
48 | NSFontAttributeName: self.textFont}];
49 | }
50 |
51 | - (NSString *)text {
52 | return _text ?: @"";
53 | }
54 |
55 | - (UIFont *)textFont {
56 | return _textFont ?: [UIFont systemFontOfSize:14];
57 | }
58 |
59 | - (UIColor *)textColor {
60 | return _textColor ?: [UIColor blackColor];
61 | }
62 |
63 | - (id)copyWithZone:(NSZone *)zone {
64 | TTGTextTagStringContent *copy = (TTGTextTagStringContent *)[super copyWithZone:zone];
65 | if (copy != nil) {
66 | copy.text = self.text;
67 | copy.textFont = self.textFont;
68 | copy.textColor = self.textColor;
69 | }
70 | return copy;
71 | }
72 |
73 | - (NSString *)description {
74 | NSMutableString *description = [NSMutableString stringWithFormat:@"<%@: ", NSStringFromClass([self class])];
75 | [description appendFormat:@"self.text=%@", self.text];
76 | [description appendString:@">"];
77 | return description;
78 | }
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/Sources/TTGTextTagStyle.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTagStyle.h
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface TTGTextTagStyle : NSObject
13 |
14 | /// Background color
15 | @property (nonatomic, copy) UIColor * _Nonnull backgroundColor; // Default is [UIColor lightGrayColor]
16 |
17 | /// Text alignment
18 | @property (nonatomic, assign) NSTextAlignment textAlignment; // Default is NSTextAlignmentCenter
19 |
20 | /// Gradient background color
21 | @property (nonatomic, assign) BOOL enableGradientBackground; // Default is NO
22 | @property (nonatomic, copy) UIColor * _Nonnull gradientBackgroundStartColor;
23 | @property (nonatomic, copy) UIColor * _Nonnull gradientBackgroundEndColor;
24 | @property (nonatomic, assign) CGPoint gradientBackgroundStartPoint;
25 | @property (nonatomic, assign) CGPoint gradientBackgroundEndPoint;
26 |
27 | /// Corner radius
28 | @property (nonatomic, assign) CGFloat cornerRadius; // Default is 4
29 | @property (nonatomic, assign) Boolean cornerTopRight;
30 | @property (nonatomic, assign) Boolean cornerTopLeft;
31 | @property (nonatomic, assign) Boolean cornerBottomRight;
32 | @property (nonatomic, assign) Boolean cornerBottomLeft;
33 |
34 | /// Border
35 | @property (nonatomic, assign) CGFloat borderWidth; // Default is [UIColor whiteColor]
36 | @property (nonatomic, copy) UIColor * _Nonnull borderColor; // Default is 1
37 |
38 | /// Shadow.
39 | @property (nonatomic, copy) UIColor * _Nonnull shadowColor; // Default is [UIColor blackColor]
40 | @property (nonatomic, assign) CGSize shadowOffset; // Default is (2, 2)
41 | @property (nonatomic, assign) CGFloat shadowRadius; // Default is 2f
42 | @property (nonatomic, assign) CGFloat shadowOpacity; // Default is 0.3f
43 |
44 | /// Extra space in width and height, will expand each tag's size
45 | @property (nonatomic, assign) CGSize extraSpace;
46 |
47 | /// Max width for a text tag. 0 and below means no max width.
48 | @property (nonatomic, assign) CGFloat maxWidth;
49 | /// Min width for a text tag. 0 and below means no min width.
50 | @property (nonatomic, assign) CGFloat minWidth;
51 |
52 | /// Max height for a text tag. 0 and below means no max height.
53 | @property (nonatomic, assign) CGFloat maxHeight;
54 | /// Min height for a text tag. 0 and below means no min height.
55 | @property (nonatomic, assign) CGFloat minHeight;
56 |
57 | /// Exact width. 0 and below means no work
58 | @property (nonatomic, assign) CGFloat exactWidth;
59 | /// Exact height. 0 and below means no work
60 | @property (nonatomic, assign) CGFloat exactHeight;
61 |
62 | /// Copy
63 | - (id _Nonnull)copyWithZone:(NSZone *_Nullable)zone;
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/Sources/TTGTextTagStyle.m:
--------------------------------------------------------------------------------
1 | //
2 | // TTGTextTagStyle.m
3 | // TTGTagCollectionView
4 | //
5 | // Created by zekunyan on 2019/5/24.
6 | // Copyright (c) 2021 zekunyan. All rights reserved.
7 | //
8 |
9 | #import "TTGTextTagStyle.h"
10 |
11 | @implementation TTGTextTagStyle
12 |
13 | - (instancetype)init {
14 | self = [super init];
15 | if (self) {
16 | _backgroundColor = [UIColor lightGrayColor];
17 | _textAlignment = NSTextAlignmentCenter;
18 | _enableGradientBackground = NO;
19 | _cornerRadius = 4;
20 | _borderColor = [UIColor whiteColor];
21 | _borderWidth = 1;
22 | _shadowColor = [UIColor blackColor];
23 | _shadowOffset = CGSizeMake(2, 2);
24 | _shadowRadius = 2;
25 | _shadowOpacity = 0.3;
26 | }
27 | return self;
28 | }
29 |
30 | - (id)copyWithZone:(NSZone *)zone {
31 | TTGTextTagStyle *copy = (TTGTextTagStyle *)[[[self class] allocWithZone:zone] init];
32 |
33 | if (copy != nil) {
34 | copy.backgroundColor = self.backgroundColor;
35 | copy.textAlignment = self.textAlignment;
36 | copy.enableGradientBackground = self.enableGradientBackground;
37 | copy.gradientBackgroundStartColor = self.gradientBackgroundStartColor;
38 | copy.gradientBackgroundEndColor = self.gradientBackgroundEndColor;
39 | copy.gradientBackgroundStartPoint = self.gradientBackgroundStartPoint;
40 | copy.gradientBackgroundEndPoint = self.gradientBackgroundEndPoint;
41 | copy.cornerRadius = self.cornerRadius;
42 | copy.cornerTopRight = self.cornerTopRight;
43 | copy.cornerTopLeft = self.cornerTopLeft;
44 | copy.cornerBottomRight = self.cornerBottomRight;
45 | copy.cornerBottomLeft = self.cornerBottomLeft;
46 | copy.borderWidth = self.borderWidth;
47 | copy.borderColor = self.borderColor;
48 | copy.shadowColor = self.shadowColor;
49 | copy.shadowOffset = self.shadowOffset;
50 | copy.shadowRadius = self.shadowRadius;
51 | copy.shadowOpacity = self.shadowOpacity;
52 | copy.extraSpace = self.extraSpace;
53 | copy.maxWidth = self.maxWidth;
54 | copy.minWidth = self.minWidth;
55 | copy.maxHeight = self.maxHeight;
56 | copy.minHeight = self.minHeight;
57 | copy.exactWidth = self.exactWidth;
58 | copy.exactHeight = self.exactHeight;
59 | }
60 |
61 | return copy;
62 | }
63 |
64 | - (UIColor *)backgroundColor {
65 | return _backgroundColor ?: [UIColor clearColor];
66 | }
67 |
68 | - (UIColor *)gradientBackgroundStartColor {
69 | return _gradientBackgroundStartColor ?: [UIColor clearColor];
70 | }
71 |
72 | - (UIColor *)gradientBackgroundEndColor {
73 | return _gradientBackgroundEndColor ?: [UIColor clearColor];
74 | }
75 |
76 | - (UIColor *)borderColor {
77 | return _borderColor ?: [UIColor clearColor];
78 | }
79 |
80 | - (UIColor *)shadowColor {
81 | return _shadowColor ?: [UIColor clearColor];
82 | }
83 |
84 | @end
85 |
--------------------------------------------------------------------------------
/TTGTagCollectionView.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "TTGTagCollectionView"
3 | s.module_name = "TTGTags"
4 | s.version = "2.4.2"
5 | s.summary = "Show rich style text tags or custom tag views in a vertical or horizontal scrollable view."
6 |
7 | s.description = <<-DESC
8 | TTGTagCollectionView is useful for showing different size tag views in a vertical or horizontal scrollable view and support Autolayout intrinsicContentSize at the same time. And if you only want to show text tags, you can use TTGTextTagCollectionView instead, which has more simple api. At the same time, It is highly customizable that many features of the text tag can be configured, like the tag font size and the background color.
9 | DESC
10 |
11 | s.homepage = "https://github.com/zekunyan/TTGTagCollectionView"
12 | s.license = 'MIT'
13 | s.author = { "zekunyan" => "zekunyan@163.com" }
14 | s.source = { :git => "https://github.com/zekunyan/TTGTagCollectionView.git", :tag => s.version.to_s }
15 | s.social_media_url = 'http://tutuge.me'
16 |
17 | s.swift_version = "5.0"
18 | s.platform = :ios, '11.0'
19 | s.requires_arc = true
20 |
21 | s.source_files = 'Sources/**/*.{h,m}'
22 | s.public_header_files = 'Sources/**/*.h'
23 | end
24 |
--------------------------------------------------------------------------------
/TTGTagCollectionView/TTGTagCollectionView.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | BF8CF4C928D344240074EB9D /* TTGTextTagStringContent.m in Sources */ = {isa = PBXBuildFile; fileRef = BF8CF4BA28D344240074EB9D /* TTGTextTagStringContent.m */; };
11 | BF8CF4CA28D344240074EB9D /* TTGTextTag.m in Sources */ = {isa = PBXBuildFile; fileRef = BF8CF4BB28D344240074EB9D /* TTGTextTag.m */; };
12 | BF8CF4CB28D344240074EB9D /* TTGTextTagAttributedStringContent.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8CF4BC28D344240074EB9D /* TTGTextTagAttributedStringContent.h */; };
13 | BF8CF4CC28D344240074EB9D /* TTGTagCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8CF4BD28D344240074EB9D /* TTGTagCollectionView.h */; };
14 | BF8CF4CD28D344240074EB9D /* TTGTextTagStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8CF4BE28D344240074EB9D /* TTGTextTagStyle.h */; };
15 | BF8CF4CE28D344240074EB9D /* TTGTagCollectionView-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8CF4BF28D344240074EB9D /* TTGTagCollectionView-Bridging-Header.h */; };
16 | BF8CF4CF28D344240074EB9D /* TTGTextTagCollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8CF4C028D344240074EB9D /* TTGTextTagCollectionView.h */; };
17 | BF8CF4D028D344240074EB9D /* TTGTextTagContent.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8CF4C128D344240074EB9D /* TTGTextTagContent.h */; };
18 | BF8CF4D128D344240074EB9D /* TTGTagCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = BF8CF4C228D344240074EB9D /* TTGTagCollectionView.m */; };
19 | BF8CF4D228D344240074EB9D /* TTGTextTagAttributedStringContent.m in Sources */ = {isa = PBXBuildFile; fileRef = BF8CF4C328D344240074EB9D /* TTGTextTagAttributedStringContent.m */; };
20 | BF8CF4D328D344240074EB9D /* TTGTextTag.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8CF4C428D344240074EB9D /* TTGTextTag.h */; };
21 | BF8CF4D428D344240074EB9D /* TTGTextTagStringContent.h in Headers */ = {isa = PBXBuildFile; fileRef = BF8CF4C528D344240074EB9D /* TTGTextTagStringContent.h */; };
22 | BF8CF4D528D344240074EB9D /* TTGTextTagStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = BF8CF4C628D344240074EB9D /* TTGTextTagStyle.m */; };
23 | BF8CF4D628D344240074EB9D /* TTGTextTagContent.m in Sources */ = {isa = PBXBuildFile; fileRef = BF8CF4C728D344240074EB9D /* TTGTextTagContent.m */; };
24 | BF8CF4D728D344240074EB9D /* TTGTextTagCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = BF8CF4C828D344240074EB9D /* TTGTextTagCollectionView.m */; };
25 | /* End PBXBuildFile section */
26 |
27 | /* Begin PBXFileReference section */
28 | BF695C4C262044EB00B5B6AC /* TTGTagCollectionView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TTGTagCollectionView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
29 | BF695C50262044EB00B5B6AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | BF8CF4BA28D344240074EB9D /* TTGTextTagStringContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTGTextTagStringContent.m; sourceTree = ""; };
31 | BF8CF4BB28D344240074EB9D /* TTGTextTag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTGTextTag.m; sourceTree = ""; };
32 | BF8CF4BC28D344240074EB9D /* TTGTextTagAttributedStringContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTGTextTagAttributedStringContent.h; sourceTree = ""; };
33 | BF8CF4BD28D344240074EB9D /* TTGTagCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTGTagCollectionView.h; sourceTree = ""; };
34 | BF8CF4BE28D344240074EB9D /* TTGTextTagStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTGTextTagStyle.h; sourceTree = ""; };
35 | BF8CF4BF28D344240074EB9D /* TTGTagCollectionView-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TTGTagCollectionView-Bridging-Header.h"; sourceTree = ""; };
36 | BF8CF4C028D344240074EB9D /* TTGTextTagCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTGTextTagCollectionView.h; sourceTree = ""; };
37 | BF8CF4C128D344240074EB9D /* TTGTextTagContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTGTextTagContent.h; sourceTree = ""; };
38 | BF8CF4C228D344240074EB9D /* TTGTagCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTGTagCollectionView.m; sourceTree = ""; };
39 | BF8CF4C328D344240074EB9D /* TTGTextTagAttributedStringContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTGTextTagAttributedStringContent.m; sourceTree = ""; };
40 | BF8CF4C428D344240074EB9D /* TTGTextTag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTGTextTag.h; sourceTree = ""; };
41 | BF8CF4C528D344240074EB9D /* TTGTextTagStringContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTGTextTagStringContent.h; sourceTree = ""; };
42 | BF8CF4C628D344240074EB9D /* TTGTextTagStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTGTextTagStyle.m; sourceTree = ""; };
43 | BF8CF4C728D344240074EB9D /* TTGTextTagContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTGTextTagContent.m; sourceTree = ""; };
44 | BF8CF4C828D344240074EB9D /* TTGTextTagCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTGTextTagCollectionView.m; sourceTree = ""; };
45 | BFE7206F262EDA69008C29D0 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
46 | /* End PBXFileReference section */
47 |
48 | /* Begin PBXFrameworksBuildPhase section */
49 | BF695C49262044EB00B5B6AC /* Frameworks */ = {
50 | isa = PBXFrameworksBuildPhase;
51 | buildActionMask = 2147483647;
52 | files = (
53 | );
54 | runOnlyForDeploymentPostprocessing = 0;
55 | };
56 | /* End PBXFrameworksBuildPhase section */
57 |
58 | /* Begin PBXGroup section */
59 | BF695C42262044EB00B5B6AC = {
60 | isa = PBXGroup;
61 | children = (
62 | BF695C4E262044EB00B5B6AC /* TTGTagCollectionView */,
63 | BF695C4D262044EB00B5B6AC /* Products */,
64 | BFE7206E262EDA69008C29D0 /* Frameworks */,
65 | );
66 | sourceTree = "";
67 | };
68 | BF695C4D262044EB00B5B6AC /* Products */ = {
69 | isa = PBXGroup;
70 | children = (
71 | BF695C4C262044EB00B5B6AC /* TTGTagCollectionView.framework */,
72 | );
73 | name = Products;
74 | sourceTree = "";
75 | };
76 | BF695C4E262044EB00B5B6AC /* TTGTagCollectionView */ = {
77 | isa = PBXGroup;
78 | children = (
79 | BF8CF4B928D344240074EB9D /* Sources */,
80 | BF695C50262044EB00B5B6AC /* Info.plist */,
81 | );
82 | path = TTGTagCollectionView;
83 | sourceTree = "";
84 | };
85 | BF8CF4B928D344240074EB9D /* Sources */ = {
86 | isa = PBXGroup;
87 | children = (
88 | BF8CF4BA28D344240074EB9D /* TTGTextTagStringContent.m */,
89 | BF8CF4BB28D344240074EB9D /* TTGTextTag.m */,
90 | BF8CF4BC28D344240074EB9D /* TTGTextTagAttributedStringContent.h */,
91 | BF8CF4BD28D344240074EB9D /* TTGTagCollectionView.h */,
92 | BF8CF4BE28D344240074EB9D /* TTGTextTagStyle.h */,
93 | BF8CF4BF28D344240074EB9D /* TTGTagCollectionView-Bridging-Header.h */,
94 | BF8CF4C028D344240074EB9D /* TTGTextTagCollectionView.h */,
95 | BF8CF4C128D344240074EB9D /* TTGTextTagContent.h */,
96 | BF8CF4C228D344240074EB9D /* TTGTagCollectionView.m */,
97 | BF8CF4C328D344240074EB9D /* TTGTextTagAttributedStringContent.m */,
98 | BF8CF4C428D344240074EB9D /* TTGTextTag.h */,
99 | BF8CF4C528D344240074EB9D /* TTGTextTagStringContent.h */,
100 | BF8CF4C628D344240074EB9D /* TTGTextTagStyle.m */,
101 | BF8CF4C728D344240074EB9D /* TTGTextTagContent.m */,
102 | BF8CF4C828D344240074EB9D /* TTGTextTagCollectionView.m */,
103 | );
104 | name = Sources;
105 | path = ../../Sources;
106 | sourceTree = "";
107 | };
108 | BFE7206E262EDA69008C29D0 /* Frameworks */ = {
109 | isa = PBXGroup;
110 | children = (
111 | BFE7206F262EDA69008C29D0 /* UIKit.framework */,
112 | );
113 | name = Frameworks;
114 | sourceTree = "";
115 | };
116 | /* End PBXGroup section */
117 |
118 | /* Begin PBXHeadersBuildPhase section */
119 | BF695C47262044EB00B5B6AC /* Headers */ = {
120 | isa = PBXHeadersBuildPhase;
121 | buildActionMask = 2147483647;
122 | files = (
123 | BF8CF4CF28D344240074EB9D /* TTGTextTagCollectionView.h in Headers */,
124 | BF8CF4D428D344240074EB9D /* TTGTextTagStringContent.h in Headers */,
125 | BF8CF4CC28D344240074EB9D /* TTGTagCollectionView.h in Headers */,
126 | BF8CF4CB28D344240074EB9D /* TTGTextTagAttributedStringContent.h in Headers */,
127 | BF8CF4CD28D344240074EB9D /* TTGTextTagStyle.h in Headers */,
128 | BF8CF4D028D344240074EB9D /* TTGTextTagContent.h in Headers */,
129 | BF8CF4D328D344240074EB9D /* TTGTextTag.h in Headers */,
130 | BF8CF4CE28D344240074EB9D /* TTGTagCollectionView-Bridging-Header.h in Headers */,
131 | );
132 | runOnlyForDeploymentPostprocessing = 0;
133 | };
134 | /* End PBXHeadersBuildPhase section */
135 |
136 | /* Begin PBXNativeTarget section */
137 | BF695C4B262044EB00B5B6AC /* TTGTagCollectionView */ = {
138 | isa = PBXNativeTarget;
139 | buildConfigurationList = BF695C54262044EB00B5B6AC /* Build configuration list for PBXNativeTarget "TTGTagCollectionView" */;
140 | buildPhases = (
141 | BF695C47262044EB00B5B6AC /* Headers */,
142 | BF695C48262044EB00B5B6AC /* Sources */,
143 | BF695C49262044EB00B5B6AC /* Frameworks */,
144 | BF695C4A262044EB00B5B6AC /* Resources */,
145 | );
146 | buildRules = (
147 | );
148 | dependencies = (
149 | );
150 | name = TTGTagCollectionView;
151 | productName = TTGTagCollectionView;
152 | productReference = BF695C4C262044EB00B5B6AC /* TTGTagCollectionView.framework */;
153 | productType = "com.apple.product-type.framework";
154 | };
155 | /* End PBXNativeTarget section */
156 |
157 | /* Begin PBXProject section */
158 | BF695C43262044EB00B5B6AC /* Project object */ = {
159 | isa = PBXProject;
160 | attributes = {
161 | LastUpgradeCheck = 1240;
162 | TargetAttributes = {
163 | BF695C4B262044EB00B5B6AC = {
164 | CreatedOnToolsVersion = 12.4;
165 | };
166 | };
167 | };
168 | buildConfigurationList = BF695C46262044EB00B5B6AC /* Build configuration list for PBXProject "TTGTagCollectionView" */;
169 | compatibilityVersion = "Xcode 9.3";
170 | developmentRegion = en;
171 | hasScannedForEncodings = 0;
172 | knownRegions = (
173 | en,
174 | Base,
175 | );
176 | mainGroup = BF695C42262044EB00B5B6AC;
177 | productRefGroup = BF695C4D262044EB00B5B6AC /* Products */;
178 | projectDirPath = "";
179 | projectRoot = "";
180 | targets = (
181 | BF695C4B262044EB00B5B6AC /* TTGTagCollectionView */,
182 | );
183 | };
184 | /* End PBXProject section */
185 |
186 | /* Begin PBXResourcesBuildPhase section */
187 | BF695C4A262044EB00B5B6AC /* Resources */ = {
188 | isa = PBXResourcesBuildPhase;
189 | buildActionMask = 2147483647;
190 | files = (
191 | );
192 | runOnlyForDeploymentPostprocessing = 0;
193 | };
194 | /* End PBXResourcesBuildPhase section */
195 |
196 | /* Begin PBXSourcesBuildPhase section */
197 | BF695C48262044EB00B5B6AC /* Sources */ = {
198 | isa = PBXSourcesBuildPhase;
199 | buildActionMask = 2147483647;
200 | files = (
201 | BF8CF4D228D344240074EB9D /* TTGTextTagAttributedStringContent.m in Sources */,
202 | BF8CF4D628D344240074EB9D /* TTGTextTagContent.m in Sources */,
203 | BF8CF4D728D344240074EB9D /* TTGTextTagCollectionView.m in Sources */,
204 | BF8CF4C928D344240074EB9D /* TTGTextTagStringContent.m in Sources */,
205 | BF8CF4D128D344240074EB9D /* TTGTagCollectionView.m in Sources */,
206 | BF8CF4D528D344240074EB9D /* TTGTextTagStyle.m in Sources */,
207 | BF8CF4CA28D344240074EB9D /* TTGTextTag.m in Sources */,
208 | );
209 | runOnlyForDeploymentPostprocessing = 0;
210 | };
211 | /* End PBXSourcesBuildPhase section */
212 |
213 | /* Begin XCBuildConfiguration section */
214 | BF695C52262044EB00B5B6AC /* Debug */ = {
215 | isa = XCBuildConfiguration;
216 | buildSettings = {
217 | ALWAYS_SEARCH_USER_PATHS = NO;
218 | CLANG_ANALYZER_NONNULL = YES;
219 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
220 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
221 | CLANG_CXX_LIBRARY = "libc++";
222 | CLANG_ENABLE_MODULES = YES;
223 | CLANG_ENABLE_OBJC_ARC = YES;
224 | CLANG_ENABLE_OBJC_WEAK = YES;
225 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
226 | CLANG_WARN_BOOL_CONVERSION = YES;
227 | CLANG_WARN_COMMA = YES;
228 | CLANG_WARN_CONSTANT_CONVERSION = YES;
229 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
230 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
231 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
232 | CLANG_WARN_EMPTY_BODY = YES;
233 | CLANG_WARN_ENUM_CONVERSION = YES;
234 | CLANG_WARN_INFINITE_RECURSION = YES;
235 | CLANG_WARN_INT_CONVERSION = YES;
236 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
237 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
238 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
240 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
241 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
242 | CLANG_WARN_STRICT_PROTOTYPES = YES;
243 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
244 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
245 | CLANG_WARN_UNREACHABLE_CODE = YES;
246 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
247 | COPY_PHASE_STRIP = NO;
248 | CURRENT_PROJECT_VERSION = 1;
249 | DEBUG_INFORMATION_FORMAT = dwarf;
250 | ENABLE_STRICT_OBJC_MSGSEND = YES;
251 | ENABLE_TESTABILITY = YES;
252 | GCC_C_LANGUAGE_STANDARD = gnu11;
253 | GCC_DYNAMIC_NO_PIC = NO;
254 | GCC_NO_COMMON_BLOCKS = YES;
255 | GCC_OPTIMIZATION_LEVEL = 0;
256 | GCC_PREPROCESSOR_DEFINITIONS = (
257 | "DEBUG=1",
258 | "$(inherited)",
259 | );
260 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
261 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
262 | GCC_WARN_UNDECLARED_SELECTOR = YES;
263 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
264 | GCC_WARN_UNUSED_FUNCTION = YES;
265 | GCC_WARN_UNUSED_VARIABLE = YES;
266 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
267 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
268 | MTL_FAST_MATH = YES;
269 | ONLY_ACTIVE_ARCH = YES;
270 | SDKROOT = iphoneos;
271 | VERSIONING_SYSTEM = "apple-generic";
272 | VERSION_INFO_PREFIX = "";
273 | };
274 | name = Debug;
275 | };
276 | BF695C53262044EB00B5B6AC /* Release */ = {
277 | isa = XCBuildConfiguration;
278 | buildSettings = {
279 | ALWAYS_SEARCH_USER_PATHS = NO;
280 | CLANG_ANALYZER_NONNULL = YES;
281 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
282 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
283 | CLANG_CXX_LIBRARY = "libc++";
284 | CLANG_ENABLE_MODULES = YES;
285 | CLANG_ENABLE_OBJC_ARC = YES;
286 | CLANG_ENABLE_OBJC_WEAK = YES;
287 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
288 | CLANG_WARN_BOOL_CONVERSION = YES;
289 | CLANG_WARN_COMMA = YES;
290 | CLANG_WARN_CONSTANT_CONVERSION = YES;
291 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
292 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
293 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
294 | CLANG_WARN_EMPTY_BODY = YES;
295 | CLANG_WARN_ENUM_CONVERSION = YES;
296 | CLANG_WARN_INFINITE_RECURSION = YES;
297 | CLANG_WARN_INT_CONVERSION = YES;
298 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
299 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
300 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
301 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
302 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
303 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
304 | CLANG_WARN_STRICT_PROTOTYPES = YES;
305 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
306 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
307 | CLANG_WARN_UNREACHABLE_CODE = YES;
308 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
309 | COPY_PHASE_STRIP = NO;
310 | CURRENT_PROJECT_VERSION = 1;
311 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
312 | ENABLE_NS_ASSERTIONS = NO;
313 | ENABLE_STRICT_OBJC_MSGSEND = YES;
314 | GCC_C_LANGUAGE_STANDARD = gnu11;
315 | GCC_NO_COMMON_BLOCKS = YES;
316 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
317 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
318 | GCC_WARN_UNDECLARED_SELECTOR = YES;
319 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
320 | GCC_WARN_UNUSED_FUNCTION = YES;
321 | GCC_WARN_UNUSED_VARIABLE = YES;
322 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
323 | MTL_ENABLE_DEBUG_INFO = NO;
324 | MTL_FAST_MATH = YES;
325 | SDKROOT = iphoneos;
326 | VALIDATE_PRODUCT = YES;
327 | VERSIONING_SYSTEM = "apple-generic";
328 | VERSION_INFO_PREFIX = "";
329 | };
330 | name = Release;
331 | };
332 | BF695C55262044EB00B5B6AC /* Debug */ = {
333 | isa = XCBuildConfiguration;
334 | buildSettings = {
335 | CODE_SIGN_IDENTITY = "Apple Development";
336 | CODE_SIGN_STYLE = Automatic;
337 | DEFINES_MODULE = YES;
338 | DEVELOPMENT_TEAM = HPQ8F9926T;
339 | DYLIB_COMPATIBILITY_VERSION = 1;
340 | DYLIB_CURRENT_VERSION = 1;
341 | DYLIB_INSTALL_NAME_BASE = "@rpath";
342 | INFOPLIST_FILE = TTGTagCollectionView/Info.plist;
343 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
344 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
345 | LD_RUNPATH_SEARCH_PATHS = (
346 | "$(inherited)",
347 | "@executable_path/Frameworks",
348 | "@loader_path/Frameworks",
349 | );
350 | PRODUCT_BUNDLE_IDENTIFIER = me.tutuge.ios.opensource.TTGTagCollectionView;
351 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
352 | SKIP_INSTALL = YES;
353 | SUPPORTS_MACCATALYST = NO;
354 | TARGETED_DEVICE_FAMILY = "1,2";
355 | };
356 | name = Debug;
357 | };
358 | BF695C56262044EB00B5B6AC /* Release */ = {
359 | isa = XCBuildConfiguration;
360 | buildSettings = {
361 | CODE_SIGN_IDENTITY = "Apple Development";
362 | CODE_SIGN_STYLE = Automatic;
363 | DEFINES_MODULE = YES;
364 | DEVELOPMENT_TEAM = HPQ8F9926T;
365 | DYLIB_COMPATIBILITY_VERSION = 1;
366 | DYLIB_CURRENT_VERSION = 1;
367 | DYLIB_INSTALL_NAME_BASE = "@rpath";
368 | INFOPLIST_FILE = TTGTagCollectionView/Info.plist;
369 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
370 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
371 | LD_RUNPATH_SEARCH_PATHS = (
372 | "$(inherited)",
373 | "@executable_path/Frameworks",
374 | "@loader_path/Frameworks",
375 | );
376 | PRODUCT_BUNDLE_IDENTIFIER = me.tutuge.ios.opensource.TTGTagCollectionView;
377 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
378 | SKIP_INSTALL = YES;
379 | SUPPORTS_MACCATALYST = NO;
380 | TARGETED_DEVICE_FAMILY = "1,2";
381 | };
382 | name = Release;
383 | };
384 | /* End XCBuildConfiguration section */
385 |
386 | /* Begin XCConfigurationList section */
387 | BF695C46262044EB00B5B6AC /* Build configuration list for PBXProject "TTGTagCollectionView" */ = {
388 | isa = XCConfigurationList;
389 | buildConfigurations = (
390 | BF695C52262044EB00B5B6AC /* Debug */,
391 | BF695C53262044EB00B5B6AC /* Release */,
392 | );
393 | defaultConfigurationIsVisible = 0;
394 | defaultConfigurationName = Release;
395 | };
396 | BF695C54262044EB00B5B6AC /* Build configuration list for PBXNativeTarget "TTGTagCollectionView" */ = {
397 | isa = XCConfigurationList;
398 | buildConfigurations = (
399 | BF695C55262044EB00B5B6AC /* Debug */,
400 | BF695C56262044EB00B5B6AC /* Release */,
401 | );
402 | defaultConfigurationIsVisible = 0;
403 | defaultConfigurationName = Release;
404 | };
405 | /* End XCConfigurationList section */
406 | };
407 | rootObject = BF695C43262044EB00B5B6AC /* Project object */;
408 | }
409 |
--------------------------------------------------------------------------------
/TTGTagCollectionView/TTGTagCollectionView.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TTGTagCollectionView/TTGTagCollectionView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TTGTagCollectionView/TTGTagCollectionView/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------