### Objective-C usage Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Objective-C equivalent of the Quick Start: creates a TTGTextTagCollectionView, builds a tag with content and style, adds it, and reloads. ```objc #import TTGTextTagCollectionView *tagView = [[TTGTextTagCollectionView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:tagView]; TTGTextTagStringContent *content = [TTGTextTagStringContent contentWithText:@"Hello"]; TTGTextTagStyle *style = [TTGTextTagStyle new]; style.backgroundColor = UIColor.systemBlueColor; style.cornerRadius = 10; style.extraSpace = CGSizeMake(12, 8); TTGTextTag *tag = [TTGTextTag tagWithContent:content style:style]; [tagView addTag:tag]; [tagView reload]; ``` -------------------------------- ### CocoaPods pod declaration Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Add this line to your Podfile and run pod install to install the library via CocoaPods. ```ruby pod 'TTGTagCollectionView' ``` -------------------------------- ### SPM repository URL Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Enter this repository URL in Xcode's Add Package Dependencies dialog to install the library via Swift Package Manager. ```text https://github.com/zekunyan/TTGTagCollectionView.git ``` -------------------------------- ### Create a TextTag with content and style Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/Resources/quick_start_02_style.html This snippet creates a TextTag by combining a TextTagStringContent with a TextTagStyle. It sets the text font and color, enables a gradient background with start and end colors, sets corner radius and extra space, and then initializes the tag. ```swift let content = TextTagStringContent(text: "Swift") content.textFont = .boldSystemFont(ofSize: 14) content.textColor = .white let style = TextTagStyle() style.enableGradientBackground = true style.gradientBackgroundStartColor = .systemBlue style.gradientBackgroundEndColor = .systemPurple style.cornerRadius = 12 style.extraSpace = CGSize(width: 14, height: 8) let tag = TextTag(content: content, style: style) ``` -------------------------------- ### Configure reordering and drag-to-delete in Objective-C Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Objective-C equivalent of the reordering and drag-to-delete setup, using the same API through TTGTags-Swift.h. Also shows programmatic tag moves with moveTagAtIndex:toIndex: and moveTagById:toIndex:. ```objc tagView.enableTagReordering = YES; tagView.enableDragToDelete = YES; [tagView moveTagAtIndex:0 toIndex:3]; [tagView moveTagById:tag.tagId toIndex:1]; tagView.dragDeleteZoneHeight = 52; tagView.dragDeleteZoneInsets = UIEdgeInsetsMake(0, 18, 12, 18); tagView.dragDeleteZoneBackgroundColor = [UIColor.systemGrayColor colorWithAlphaComponent:0.92]; tagView.dragDeleteZoneHighlightedBackgroundColor = [UIColor.systemPinkColor colorWithAlphaComponent:0.96]; tagView.dragDeleteZoneText = @"Drop tag to remove"; tagView.dragDeleteZoneImage = [UIImage systemImageNamed:@"trash.fill"]; ``` -------------------------------- ### Configure a TextTag model Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Configure a TextTag instance: set content and style for normal and selected states, toggle selection, observe selection changes, attach arbitrary objects, and set accessibility properties. The selectedContent and selectedStyle fall back to copies of the normal ones if not set. Use rightfulContent and rightfulStyle to get the active values based on the selected state. ```swift let tag = TextTag() // Content & style for normal / selected state tag.content = TextTagStringContent(text: "Label") tag.style = TextTagStyle() tag.selectedContent = TextTagStringContent(text: "Selected") // optional, falls back to content copy tag.selectedStyle = TextTagStyle() // optional, falls back to style copy // Selection tag.selected = false tag.onSelectStateChanged = { selected in print(selected) } // Attach any object tag.attachment = myModel // Accessibility tag.enableAutoDetectAccessibility = true // auto sets label + traits from content // or manually: tag.isAccessibilityElement = true tag.accessibilityLabel = "My tag" tag.accessibilityHint = "Double tap to select" tag.accessibilityTraits = .button // Current active content / style (respects selected state) let activeContent = tag.rightfulContent let activeStyle = tag.rightfulStyle ``` -------------------------------- ### Enable swipe selection with delegate methods Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Enable swipe selection on TextTagCollectionView. It is opt-in, selects only unselected tags, and respects selectionLimit. Implement the delegate methods to control and observe swipe selection. The Objective-C snippet shows the equivalent setup. ```swift tagView.enableSwipeSelection = true tagView.selectionLimit = 6 tagView.delegate = self func textTagCollectionView(_ collectionView: TextTagCollectionView, canSwipeSelectTag tag: TextTag, at index: Int) -> Bool { return true } func textTagCollectionView(_ collectionView: TextTagCollectionView, didSwipeSelectTag tag: TextTag, at index: Int) { print("swipe selected \(index)") } ``` ```objc tagView.enableSwipeSelection = YES; tagView.selectionLimit = 6; ``` -------------------------------- ### Configure TextTagStyle properties Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Configure a TextTagStyle instance with background, gradient, corner, border, shadow, and size properties. numberOfLines 0 means unlimited multiline; minWidth 0 means no limit; exactWidth 0 means auto. Corner flags control individual corners; by default all corners are rounded. ```swift let style = TextTagStyle() // Background style.backgroundColor = .systemBlue style.textAlignment = .center style.numberOfLines = 1 // 0 = unlimited multiline style.lineBreakMode = .byTruncatingTail // Gradient background style.enableGradientBackground = true style.gradientBackgroundStartColor = .systemBlue style.gradientBackgroundEndColor = .systemPurple style.gradientBackgroundStartPoint = CGPoint(x: 0, y: 0.5) style.gradientBackgroundEndPoint = CGPoint(x: 1, y: 0.5) // Corner (all corners by default; set individual flags for per-corner control) style.cornerRadius = 14 style.cornerTopLeft = true style.cornerTopRight = true style.cornerBottomLeft = false style.cornerBottomRight = false // Border style.borderWidth = 1 style.borderColor = .white // Shadow style.shadowColor = .black style.shadowOffset = CGSize(width: 2, height: 2) style.shadowRadius = 2 style.shadowOpacity = 0.3 // Size style.extraSpace = CGSize(width: 12, height: 6) // padding style.minWidth = 60 // 0 = no limit style.maxWidth = 200 style.exactWidth = 0 // 0 = auto style.exactHeight = 32 ``` -------------------------------- ### Configure selected style and selection limit with delegate callback Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/Resources/quick_start_03_selection.html Assigns a selectedStyle to a tag, sets selectionLimit to 3, and sets the delegate to self. The delegate method textTagCollectionView(_:didTapTag:at:) prints the index and selected state when a tag is tapped. ```swift let selectedStyle = TextTagStyle() selectedStyle.backgroundColor = .systemOrange selectedStyle.cornerRadius = 12 selectedStyle.extraSpace = CGSize(width: 14, height: 8) tag.selectedStyle = selectedStyle tagView.selectionLimit = 3 tagView.delegate = self func textTagCollectionView(_ view: TextTagCollectionView, didTapTag tag: TextTag, at index: Int) { print(index, tag.selected) } ``` -------------------------------- ### Build TextTag content and style Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Builds a TextTag from content and style, adds it to the tagView, and reloads. The same model also carries selection state, accessibility metadata, and optional attachment data. ```swift let content = TextTagStringContent(text: "Swift") content.textFont = .boldSystemFont(ofSize: 14) content.textColor = .white let style = TextTagStyle() style.enableGradientBackground = true style.gradientBackgroundStartColor = .systemBlue style.gradientBackgroundEndColor = .systemPurple style.cornerRadius = 12 style.extraSpace = CGSize(width: 14, height: 8) let tag = TextTag(content: content, style: style) tagView.add(tag: tag) tagView.reload() ``` -------------------------------- ### Create multiline text tag with TextTag Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Create a multiline text tag by setting numberOfLines to 0, maxWidth to 180, and lineBreakMode to .byWordWrapping on the style, then instantiate a TextTag with the content and style. ```swift let content = TextTagStringContent(text: "Long filter label that can wrap") let style = TextTagStyle() style.numberOfLines = 0 style.maxWidth = 180 style.lineBreakMode = .byWordWrapping let tag = TextTag(content: content, style: style) ``` -------------------------------- ### Configure tag view layout properties Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/Resources/quick_start_04_layout.html Sets alignment to fill by expanding width, horizontal and vertical spacing to 8, content inset to 12 on all sides, horizontal scroll direction, limits to 2 lines, hides the horizontal scroll indicator, and reloads the view. ```swift tagView.alignment = .fillByExpandingWidth tagView.horizontalSpacing = 8 tagView.verticalSpacing = 8 tagView.contentInset = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12) tagView.scrollDirection = .horizontal tagView.numberOfLines = 2 tagView.showsHorizontalScrollIndicator = false tagView.reload() ``` -------------------------------- ### Configure tagView layout and tap callbacks Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Configure layout properties on a tagView: scrollDirection (default .vertical), alignment, horizontalDistribution, contentVerticalAlignment, numberOfLines (0 = unlimited), selectionLimit (0 = unlimited), spacing, and contentInset. For AutoLayout manual height, set manualCalculateHeight to true and preferredMaxLayoutWidth. Tap callbacks onTapBlankArea and onTapAllArea provide closures without needing a delegate. ```swift tagView.scrollDirection = .vertical // .vertical (default) or .horizontal tagView.alignment = .left // see Alignment below tagView.horizontalDistribution = .rowMajor tagView.contentVerticalAlignment = .top tagView.numberOfLines = 0 // 0 = unlimited tagView.selectionLimit = 3 // 0 = unlimited tagView.horizontalSpacing = 8 tagView.verticalSpacing = 8 tagView.contentInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) // AutoLayout manual height tagView.manualCalculateHeight = true tagView.preferredMaxLayoutWidth = 320 // Tap callbacks (no delegate needed) tagView.onTapBlankArea = { point in print("tapped blank at \(point)") } tagView.onTapAllArea = { point in print("tapped anywhere at \(point)") } ``` -------------------------------- ### Create TextTagStringContent and TextTagAttributedStringContent Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Create tag content using TextTagStringContent for plain text and TextTagAttributedStringContent for rich text via NSAttributedString. The plain text content allows setting textFont and textColor; the attributed content takes an NSAttributedString with attributes like foregroundColor and font. ```swift // Plain text let c1 = TextTagStringContent(text: "Hello") c1.textFont = .systemFont(ofSize: 14) c1.textColor = .darkText // Rich text via NSAttributedString let attrs: [NSAttributedString.Key: Any] = [ .foregroundColor: UIColor.systemRed, .font: UIFont.boldSystemFont(ofSize: 16) ] let c2 = TextTagAttributedStringContent( attributedText: NSAttributedString(string: "Rich", attributes: attrs) ) ``` -------------------------------- ### Implement TextTagCollectionViewDelegate methods Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Set the delegate on a TextTagCollectionView and implement the TextTagCollectionViewDelegate methods to handle tap, swipe-select, and content-size updates. The canTapTag and canSwipeSelectTag methods return Bool to enable or disable the interaction; didTapTag prints the tag's text and selected state, didSwipeSelectTag prints the index, and updateContentSize is called when the content size changes, e.g., to update a height constraint. ```swift tagView.delegate = self // TextTagCollectionViewDelegate func textTagCollectionView(_ collectionView: TextTagCollectionView, canTapTag tag: TextTag, at index: Int) -> Bool { true } func textTagCollectionView(_ collectionView: TextTagCollectionView, didTapTag tag: TextTag, at index: Int) { print("tapped: \(tag.rightfulContent.contentAttributedString.string), selected: \(tag.selected)") } func textTagCollectionView(_ collectionView: TextTagCollectionView, canSwipeSelectTag tag: TextTag, at index: Int) -> Bool { true } func textTagCollectionView(_ collectionView: TextTagCollectionView, didSwipeSelectTag tag: TextTag, at index: Int) { print("swipe selected: \(index)") } func textTagCollectionView(_ collectionView: TextTagCollectionView, updateContentSize contentSize: CGSize) { // e.g. update a height constraint } ``` -------------------------------- ### Enable reordering and drag-to-delete with TextTagCollectionView delegate Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Enable reordering and drag-to-delete on a TextTagCollectionView, optionally styling the delete zone. The delegate methods control and report move/delete operations; the print statements show the resulting index changes. ```swift tagView.enableTagReordering = true tagView.enableDragToDelete = true tagView.enableTagSelection = false tagView.delegate = self // Optional delete-zone styling tagView.dragDeleteZoneHeight = 52 tagView.dragDeleteZoneInsets = UIEdgeInsets(top: 0, left: 18, bottom: 12, right: 18) tagView.dragDeleteZoneCornerRadius = 16 tagView.dragDeleteZoneBackgroundColor = UIColor.systemGray.withAlphaComponent(0.92) tagView.dragDeleteZoneHighlightedBackgroundColor = UIColor.systemPink.withAlphaComponent(0.96) tagView.dragDeleteZoneText = "Drop tag to remove" tagView.dragDeleteZoneTextColor = .white tagView.dragDeleteZoneFont = .systemFont(ofSize: 15, weight: .semibold) tagView.dragDeleteZoneImage = UIImage(systemName: "trash.fill") tagView.dragDeleteZoneImageTintColor = .white ``` ```swift func textTagCollectionView(_ collectionView: TextTagCollectionView, canMoveTag tag: TextTag, fromIndex: Int, toIndex: Int) -> Bool { return true } func textTagCollectionView(_ collectionView: TextTagCollectionView, didMoveTag tag: TextTag, fromIndex: Int, toIndex: Int) { print("moved \(fromIndex) -> \(toIndex)") } func textTagCollectionView(_ collectionView: TextTagCollectionView, canDeleteTag tag: TextTag, at index: Int) -> Bool { return true } func textTagCollectionView(_ collectionView: TextTagCollectionView, didDeleteTag tag: TextTag, at index: Int) { print("deleted \(index)") } ``` -------------------------------- ### Add selected states Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Configures a selected style, sets the selection limit to 3, and assigns the delegate. selectedStyle is applied automatically when a tag is selected. ```swift let selectedStyle = TextTagStyle() selectedStyle.backgroundColor = .systemOrange selectedStyle.cornerRadius = 12 selectedStyle.extraSpace = CGSize(width: 14, height: 8) tag.selectedStyle = selectedStyle tagView.selectionLimit = 3 tagView.delegate = self ``` -------------------------------- ### Precompute tag size in Objective-C with TTGTextTagCollectionView contentSizeForTags: Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Objective-C equivalent of the Swift contentSize(for:width:...) API, available through TTGTags-Swift.h. Use the same parameters to precompute tag layout size. ```objc CGSize tagSize = [TTGTextTagCollectionView contentSizeForTags:tags width:availableTagWidth scrollDirection:TTGTagCollectionScrollDirectionVertical alignment:TTGTagCollectionAlignmentFillByExpandingWidth horizontalDistribution:TTGTagCollectionHorizontalDistributionRowMajor numberOfLines:0 horizontalSpacing:8 verticalSpacing:8 contentInset:UIEdgeInsetsMake(4, 0, 4, 0)]; ``` -------------------------------- ### Create TextTagCollectionView with Auto Layout Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/Resources/quick_start_01_create.html Use this snippet to create a TextTagCollectionView and add it to your view hierarchy. It sets translatesAutoresizingMaskIntoConstraints to false and activates constraints for leading, trailing, and top anchors. ```swift import TTGTags let tagView = TextTagCollectionView() tagView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tagView) NSLayoutConstraint.activate([ tagView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16), tagView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16), tagView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24) ]) ``` -------------------------------- ### Precompute tag size with TextTagCollectionView.contentSize(for:width:...) Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Precompute tag layout size for a table cell to cache row height. Use the returned tagSize to calculate rowHeight as titleHeight + tagSize.height + verticalPadding. ```swift let tagSize = TextTagCollectionView.contentSize( for: tags, width: availableTagWidth, scrollDirection: .vertical, alignment: .fillByExpandingWidth, horizontalDistribution: .rowMajor, numberOfLines: 0, horizontalSpacing: 8, verticalSpacing: 8, contentInset: UIEdgeInsets(top: 4, left: 0, bottom: 4, right: 0) ) let rowHeight = titleHeight + tagSize.height + verticalPadding ``` -------------------------------- ### Set horizontalDistribution and contentVerticalAlignment Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Set horizontalDistribution to .rowMajor for natural reading order in horizontal multi-line rows (default in 3.1) or .columnMajor to preserve the old round-robin column-first behavior. Also shows setting contentVerticalAlignment to .center for centering content inside a fixed-height tag surface. ```swift // Natural reading order in horizontal multi-line rows (default in 3.1) tagView.scrollDirection = .horizontal tagView.numberOfLines = 2 tagView.horizontalDistribution = .rowMajor // Preserve the old round-robin column-first behavior when needed tagView.horizontalDistribution = .columnMajor // Center content inside a fixed-height tag surface tagView.contentVerticalAlignment = .center ``` -------------------------------- ### Hit-test a tag at a point Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Hit-testing: find the index of the tag at a given touch point. Returns NSNotFound if no tag is hit. ```swift let index = tagView.indexOfTag(at: touchPoint) // NSNotFound if missed ``` -------------------------------- ### Migrate Objective-C import to Swift umbrella header Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Shows the single required change for migrating existing Objective-C call sites from version 2.x to 3.0: replace the old header import with the Swift generated umbrella header. All class names, selectors, and enum cases are preserved via @objc(TTGXxx) aliases. ```objc // Before (2.x) #import // After (3.0+) #import ``` -------------------------------- ### Add SPM dependency in Package.swift Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Add this dependency entry to your Package.swift file to use TTGTagCollectionView version 3.3.0 or later. ```swift dependencies: [ .package(url: "https://github.com/zekunyan/TTGTagCollectionView.git", from: "3.3.0") ] ``` -------------------------------- ### Scroll to a tag Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Scroll the collection view to a specific tag, either by index or by tag ID, with a specified scroll position and animation flag. ```swift tagView.scrollToTag(at: 12, position: .center, animated: true) tagView.scrollToTag(byId: tag.tagId, position: .end, animated: true) ``` -------------------------------- ### Use TagCollectionView with custom UIView tags Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Use TagCollectionView with custom UIView tags. Implement the data source and delegate methods to provide tag views, sizes, and selection handling; call reload() to refresh. Layout properties are identical to TextTagCollectionView. ```swift tagCollectionView.dataSource = self tagCollectionView.delegate = self // TagCollectionViewDataSource func numberOfTags(in tagCollectionView: TagCollectionView) -> Int { items.count } func tagCollectionView(_ tagCollectionView: TagCollectionView, tagViewFor index: Int) -> UIView { myViews[index] } // TagCollectionViewDelegate func tagCollectionView(_ tagCollectionView: TagCollectionView, sizeForTagAt index: Int) -> CGSize { myViews[index].frame.size } func tagCollectionView(_ tagCollectionView: TagCollectionView, didSelectTag tagView: UIView, at index: Int) { print("selected \(index)") } func tagCollectionView(_ tagCollectionView: TagCollectionView, updateContentSize contentSize: CGSize) { } // Reload tagCollectionView.reload() ``` -------------------------------- ### Mutate tags in TextTagCollectionView Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Shows the full mutation API for TextTagCollectionView: add, insert, update, remove, move, and query tags. Move operations automatically reload the view. After any mutation, call reload() to refresh the display. ```swift // Add tagView.add(tag: tag) tagView.add(tags: [tag1, tag2]) // Insert tagView.insert(tag: tag, at: 0) tagView.insert(tags: [tag1, tag2], at: 2) // Update tagView.updateTag(at: 0, selected: true) tagView.updateTag(at: 0, with: newTag) tagView.updateTag(byId: tag.tagId, selected: true) tagView.updateTag(byId: tag.tagId, with: newTag) // Remove tagView.remove(tag: tag) tagView.removeTag(byId: tag.tagId) tagView.removeTag(at: 0) tagView.removeAllTags() // Move (auto reloads) tagView.moveTag(at: 0, to: 3) tagView.moveTag(byId: tag.tagId, to: 1) // Query let tag = tagView.getTag(at: 0) let sameTag = tagView.getTag(byId: tagId) let index = tagView.indexOfTag(byId: tagId) let tags = tagView.getTags(in: NSRange(location: 0, length: 3)) let all = tagView.allTags() let selected = tagView.allSelectedTags() let unselected = tagView.allNotSelectedTags() // Reload (required after any mutation) tagView.reload() ``` -------------------------------- ### Clear measurement cache with TextTagCollectionView.clearMeasurementCache() Source: https://github.com/zekunyan/ttgtagcollectionview/blob/master/README.md Clears both measurement and layout caches. Use when data changes globally or when benchmarking a cold path. ```swift TextTagCollectionView.clearMeasurementCache() ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.