forked from shadowfacts/Tusker
Add select more photos option to asset picker
This commit is contained in:
parent
dc1eb3d6f0
commit
6138fc7748
|
@ -90,7 +90,6 @@
|
|||
D623A5412635FB3C0095BD04 /* PollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A5402635FB3C0095BD04 /* PollOptionView.swift */; };
|
||||
D623A543263634100095BD04 /* PollOptionCheckboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D623A542263634100095BD04 /* PollOptionCheckboxView.swift */; };
|
||||
D625E4822588262A0074BB2B /* DraggableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D625E4812588262A0074BB2B /* DraggableTableViewCell.swift */; };
|
||||
D626493323BD751600612E6E /* ShowCameraCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D626493123BD751600612E6E /* ShowCameraCollectionViewCell.xib */; };
|
||||
D626493523BD94CE00612E6E /* CompositionAttachmentData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D626493423BD94CE00612E6E /* CompositionAttachmentData.swift */; };
|
||||
D626493823C0FD0000612E6E /* AllPhotosTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D626493623C0FD0000612E6E /* AllPhotosTableViewCell.swift */; };
|
||||
D626493923C0FD0000612E6E /* AllPhotosTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D626493723C0FD0000612E6E /* AllPhotosTableViewCell.xib */; };
|
||||
|
@ -203,6 +202,7 @@
|
|||
D681E4D9246E346E0053414F /* AccountActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */; };
|
||||
D68232F72464F4FD00325FB8 /* ComposeDrawingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */; };
|
||||
D686BBE324FBF8110068E6AA /* WrappedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D686BBE224FBF8110068E6AA /* WrappedProgressView.swift */; };
|
||||
D68ACE5D279B1ABA001CE8EB /* AssetPickerControlCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68ACE5C279B1ABA001CE8EB /* AssetPickerControlCollectionViewCell.swift */; };
|
||||
D68C2AE325869BAB00548EFF /* AuxiliarySceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68C2AE225869BAB00548EFF /* AuxiliarySceneDelegate.swift */; };
|
||||
D68E525B24A3D77E0054355A /* TuskerRootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68E525A24A3D77E0054355A /* TuskerRootViewController.swift */; };
|
||||
D68E525D24A3E8F00054355A /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68E525C24A3E8F00054355A /* SearchViewController.swift */; };
|
||||
|
@ -495,7 +495,6 @@
|
|||
D623A5402635FB3C0095BD04 /* PollOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionView.swift; sourceTree = "<group>"; };
|
||||
D623A542263634100095BD04 /* PollOptionCheckboxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionCheckboxView.swift; sourceTree = "<group>"; };
|
||||
D625E4812588262A0074BB2B /* DraggableTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D626493123BD751600612E6E /* ShowCameraCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShowCameraCollectionViewCell.xib; sourceTree = "<group>"; };
|
||||
D626493423BD94CE00612E6E /* CompositionAttachmentData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionAttachmentData.swift; sourceTree = "<group>"; };
|
||||
D626493623C0FD0000612E6E /* AllPhotosTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllPhotosTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D626493723C0FD0000612E6E /* AllPhotosTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AllPhotosTableViewCell.xib; sourceTree = "<group>"; };
|
||||
|
@ -611,6 +610,7 @@
|
|||
D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountActivityItemSource.swift; sourceTree = "<group>"; };
|
||||
D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeDrawingViewController.swift; sourceTree = "<group>"; };
|
||||
D686BBE224FBF8110068E6AA /* WrappedProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WrappedProgressView.swift; sourceTree = "<group>"; };
|
||||
D68ACE5C279B1ABA001CE8EB /* AssetPickerControlCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetPickerControlCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
D68C2AE225869BAB00548EFF /* AuxiliarySceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuxiliarySceneDelegate.swift; sourceTree = "<group>"; };
|
||||
D68E525A24A3D77E0054355A /* TuskerRootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TuskerRootViewController.swift; sourceTree = "<group>"; };
|
||||
D68E525C24A3E8F00054355A /* SearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -974,11 +974,11 @@
|
|||
children = (
|
||||
D6B053A923BD2F1400A066FA /* AssetCollectionViewCell.swift */,
|
||||
D6B053AA23BD2F1400A066FA /* AssetCollectionViewCell.xib */,
|
||||
D626493123BD751600612E6E /* ShowCameraCollectionViewCell.xib */,
|
||||
D626493623C0FD0000612E6E /* AllPhotosTableViewCell.swift */,
|
||||
D626493723C0FD0000612E6E /* AllPhotosTableViewCell.xib */,
|
||||
D626493A23C1000300612E6E /* AlbumTableViewCell.swift */,
|
||||
D626493B23C1000300612E6E /* AlbumTableViewCell.xib */,
|
||||
D68ACE5C279B1ABA001CE8EB /* AssetPickerControlCollectionViewCell.swift */,
|
||||
);
|
||||
path = "Asset Picker";
|
||||
sourceTree = "<group>";
|
||||
|
@ -1923,7 +1923,6 @@
|
|||
D6289E84217B795D0003D1D7 /* LargeImageViewController.xib in Resources */,
|
||||
D6093FB125BE0B01004811E6 /* TrendingHashtagTableViewCell.xib in Resources */,
|
||||
D627FF79217E950100CC0648 /* DraftsTableViewController.xib in Resources */,
|
||||
D626493323BD751600612E6E /* ShowCameraCollectionViewCell.xib in Resources */,
|
||||
D626493D23C1000300612E6E /* AlbumTableViewCell.xib in Resources */,
|
||||
D627944723A6AC9300D38C68 /* BasicTableViewCell.xib in Resources */,
|
||||
D64BC19023C18B9D000D0238 /* FollowRequestNotificationTableViewCell.xib in Resources */,
|
||||
|
@ -2096,6 +2095,7 @@
|
|||
D627944F23A9C99800D38C68 /* EditListAccountsViewController.swift in Sources */,
|
||||
D6945C3423AC6431005C403C /* AddSavedHashtagViewController.swift in Sources */,
|
||||
D627943723A552C200D38C68 /* BookmarkStatusActivity.swift in Sources */,
|
||||
D68ACE5D279B1ABA001CE8EB /* AssetPickerControlCollectionViewCell.swift in Sources */,
|
||||
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */,
|
||||
D6AC956723C4347E008C9946 /* MainSceneDelegate.swift in Sources */,
|
||||
D6311C5025B3765B00B27539 /* ImageDataCache.swift in Sources */,
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Post videos from the camera.</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Save photos directly from other people's posts.</string>
|
||||
<string>Save photos directly from other people's posts.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Post photos from the photo library.</string>
|
||||
<key>NSUserActivityTypes</key>
|
||||
|
|
|
@ -18,16 +18,13 @@ protocol AssetCollectionViewControllerDelegate: AnyObject {
|
|||
func captureFromCamera()
|
||||
}
|
||||
|
||||
class AssetCollectionViewController: UICollectionViewController {
|
||||
class AssetCollectionViewController: UIViewController, UICollectionViewDelegate {
|
||||
|
||||
weak var delegate: AssetCollectionViewControllerDelegate?
|
||||
|
||||
private var collectionView: UICollectionView!
|
||||
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
||||
private var flowLayout: UICollectionViewFlowLayout {
|
||||
return collectionViewLayout as! UICollectionViewFlowLayout
|
||||
}
|
||||
|
||||
private var availableWidth: CGFloat!
|
||||
private var thumbnailSize: CGSize!
|
||||
|
||||
private let imageManager = PHCachingImageManager()
|
||||
|
@ -41,7 +38,7 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
}
|
||||
|
||||
init() {
|
||||
super.init(collectionViewLayout: UICollectionViewFlowLayout())
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
|
@ -51,6 +48,17 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3), heightDimension: .fractionalWidth(1/3))
|
||||
let item = NSCollectionLayoutItem(layoutSize: itemSize)
|
||||
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalWidth(1/3))
|
||||
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 3)
|
||||
group.interItemSpacing = .fixed(4)
|
||||
let section = NSCollectionLayoutSection(group: group)
|
||||
let layout = UICollectionViewCompositionalLayout(section: section)
|
||||
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
||||
collectionView.delegate = self
|
||||
view.addSubview(collectionView)
|
||||
|
||||
// use the safe area layout guide instead of letting it automatically use the safe area insets
|
||||
// because otherwise, when presented in a popover with the arrow on the left or right side,
|
||||
// the collection view content will be cut off by the width of the arrow because the popover
|
||||
|
@ -73,16 +81,24 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
collectionView.allowsSelection = true
|
||||
|
||||
collectionView.register(UINib(nibName: "AssetCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: reuseIdentifier)
|
||||
collectionView.register(UINib(nibName: "ShowCameraCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: cameraReuseIdentifier)
|
||||
|
||||
let scale = UIScreen.main.scale
|
||||
let cellSize = flowLayout.itemSize
|
||||
thumbnailSize = CGSize(width: cellSize.width * scale, height: cellSize.height * scale)
|
||||
let controlCell = UICollectionView.CellRegistration<AssetPickerControlCollectionViewCell, Item> { cell, indexPath, itemIdentifier in
|
||||
switch itemIdentifier {
|
||||
case .showCamera:
|
||||
cell.imageView.image = UIImage(systemName: "camera")
|
||||
cell.label.text = "Take a Photo"
|
||||
case .changeLimitedSelection:
|
||||
cell.imageView.image = UIImage(systemName: "photo.on.rectangle.angled")
|
||||
cell.label.text = "Select More Photos"
|
||||
case .asset(_):
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: { (collectionView, indexPath, item) -> UICollectionViewCell? in
|
||||
switch item {
|
||||
case .showCamera:
|
||||
return collectionView.dequeueReusableCell(withReuseIdentifier: cameraReuseIdentifier, for: indexPath)
|
||||
case .showCamera, .changeLimitedSelection:
|
||||
return collectionView.dequeueConfiguredReusableCell(using: controlCell, for: indexPath, item: item)
|
||||
case let .asset(asset):
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! AssetCollectionViewCell
|
||||
|
||||
|
@ -107,30 +123,23 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
let interactivePopGesture = navigationController?.interactivePopGestureRecognizer {
|
||||
singleFingerPanGesture.require(toFail: interactivePopGesture)
|
||||
}
|
||||
|
||||
PHPhotoLibrary.shared().register(self)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
let scale = UIScreen.main.scale
|
||||
let cellWidth = view.bounds.width / 3
|
||||
thumbnailSize = CGSize(width: cellWidth * scale, height: cellWidth * scale)
|
||||
|
||||
loadAssets()
|
||||
}
|
||||
|
||||
override func viewWillLayoutSubviews() {
|
||||
super.viewWillLayoutSubviews()
|
||||
|
||||
let availableWidth = view.bounds.inset(by: view.safeAreaInsets).width
|
||||
|
||||
if self.availableWidth != availableWidth {
|
||||
self.availableWidth = availableWidth
|
||||
|
||||
let size = (availableWidth - 8) / 3
|
||||
flowLayout.itemSize = CGSize(width: size, height: size)
|
||||
flowLayout.minimumInteritemSpacing = 4
|
||||
flowLayout.minimumLineSpacing = 4
|
||||
}
|
||||
}
|
||||
|
||||
private func loadAssets() {
|
||||
var items = [Item.showCamera]
|
||||
|
||||
switch PHPhotoLibrary.authorizationStatus(for: .readWrite) {
|
||||
case .notDetermined:
|
||||
PHPhotoLibrary.requestAuthorization(for: .readWrite) { (_) in
|
||||
|
@ -142,8 +151,11 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
// todo: better UI for this
|
||||
return
|
||||
|
||||
case .authorized, .limited:
|
||||
// todo: show "add more" button for limited access
|
||||
case .authorized:
|
||||
break
|
||||
|
||||
case .limited:
|
||||
items.append(.changeLimitedSelection)
|
||||
break
|
||||
|
||||
@unknown default:
|
||||
|
@ -156,7 +168,6 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
fetchResult = fetchAssets(with: options)
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||
snapshot.appendSections([.assets])
|
||||
var items: [Item] = [.showCamera]
|
||||
fetchResult.enumerateObjects { (asset, _, _) in
|
||||
items.append(.asset(asset))
|
||||
}
|
||||
|
@ -176,11 +187,11 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
|
||||
// MARK: UICollectionViewDelegate
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool {
|
||||
func collectionView(_ collectionView: UICollectionView, shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||
guard let item = dataSource.itemIdentifier(for: indexPath) else { return false }
|
||||
if let delegate = delegate,
|
||||
case let .asset(asset) = item {
|
||||
|
@ -189,29 +200,32 @@ class AssetCollectionViewController: UICollectionViewController {
|
|||
return true
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
guard let item = dataSource.itemIdentifier(for: indexPath) else { return }
|
||||
switch item {
|
||||
case .showCamera:
|
||||
collectionView.deselectItem(at: indexPath, animated: false)
|
||||
delegate?.captureFromCamera()
|
||||
case .changeLimitedSelection:
|
||||
// todo: change observer
|
||||
PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: self)
|
||||
case .asset(_):
|
||||
updateItemsSelectedCount()
|
||||
}
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||
updateItemsSelectedCount()
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||
func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||
guard case let .asset(asset) = dataSource.itemIdentifier(for: indexPath) else { return nil }
|
||||
return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: { () -> UIViewController? in
|
||||
return AssetPreviewViewController(asset: asset)
|
||||
}, actionProvider: nil)
|
||||
}
|
||||
|
||||
override func collectionView(_ collectionView: UICollectionView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
|
||||
func collectionView(_ collectionView: UICollectionView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
|
||||
if let indexPath = (configuration.identifier as? NSIndexPath) as IndexPath?,
|
||||
let cell = collectionView.cellForItem(at: indexPath) as? AssetCollectionViewCell {
|
||||
let parameters = UIPreviewParameters()
|
||||
|
@ -237,6 +251,15 @@ extension AssetCollectionViewController {
|
|||
}
|
||||
enum Item: Hashable {
|
||||
case showCamera
|
||||
case changeLimitedSelection
|
||||
case asset(PHAsset)
|
||||
}
|
||||
}
|
||||
|
||||
extension AssetCollectionViewController: PHPhotoLibraryChangeObserver {
|
||||
func photoLibraryDidChange(_ changeInstance: PHChange) {
|
||||
DispatchQueue.main.async {
|
||||
self.loadAssets()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// AssetPickerControlCollectionViewCell.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 1/21/22.
|
||||
// Copyright © 2022 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AssetPickerControlCollectionViewCell: UICollectionViewCell {
|
||||
|
||||
let imageView = UIImageView()
|
||||
let label = UILabel()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
imageView.contentMode = .scaleAspectFit
|
||||
imageView.setContentHuggingPriority(.defaultLow, for: .vertical)
|
||||
|
||||
label.font = .preferredFont(forTextStyle: .caption1)
|
||||
label.textAlignment = .center
|
||||
|
||||
let stackView = UIStackView(arrangedSubviews: [
|
||||
imageView,
|
||||
label,
|
||||
])
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.axis = .vertical
|
||||
stackView.alignment = .center
|
||||
addSubview(stackView)
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
stackView.topAnchor.constraint(equalTo: topAnchor, constant: 8),
|
||||
stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8),
|
||||
|
||||
imageView.widthAnchor.constraint(equalTo: widthAnchor, constant: -32)
|
||||
])
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX">
|
||||
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="camera" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="fUY-i2-EtY">
|
||||
<rect key="frame" x="16" y="16.5" width="48" height="46"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="fUY-i2-EtY" secondAttribute="bottom" constant="16" id="HkO-Cn-2Na"/>
|
||||
<constraint firstItem="fUY-i2-EtY" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="16" id="bUq-pX-5XL"/>
|
||||
<constraint firstAttribute="trailing" secondItem="fUY-i2-EtY" secondAttribute="trailing" constant="16" id="fyg-fN-FJu"/>
|
||||
<constraint firstItem="fUY-i2-EtY" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="16" id="oOU-Tc-Z5T"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
|
||||
<point key="canvasLocation" x="132" y="154"/>
|
||||
</collectionViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="camera" catalog="system" width="64" height="48"/>
|
||||
</resources>
|
||||
</document>
|
Loading…
Reference in New Issue