in my code which is all listed below in the first class the user drags rectangles around and can save how it looks. The middle class is a library where you can see all of the saved artwork. In the last class you see the full screen pic of the saved image. What I would like to do is in the middle class edit the saved image so you can rearranged the boxes. I don’t know if this is something you have to create a file to do or use file manager. Think of this as several different photoshop files that I would like to edit and save their design.
import UIKit;import CoreData
class ViewController: UIViewController {
var rectangleB = UIButton()
var arrTextFields = [UIImageView]()
var libaryB = UIButton()
var ww = 80
var currentView: UIView?
var saveB = UIButton()
var clearB = UIButton()
override func viewDidLoad() {
view.backgroundColor = .white
[rectangleB, saveB, libaryB, clearB].forEach {
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
$0.layer.borderWidth = 1
$0.backgroundColor = UIColor(
red: .random(in: 0.5...0.7),
green: .random(in: 0.0...1),
blue: .random(in: 0.3...0.5),
alpha: 1
)
$0.layer.borderWidth = 1
if let textfield = $0 as? UITextField {
textfield.textAlignment = .center
textfield.inputAccessoryView = createToolbar()
}
if let label = $0 as? UILabel {
label.textAlignment = .center
}
if let button = $0 as? UIButton {
button.setTitleColor(.black, for: .normal)
}
}
libaryB.setTitle("Library", for: .normal)
saveB.setTitle("Save", for: .normal)
libaryB.addTarget(self, action: #selector(libraryBtn), for: .touchDown)
// note that I changed some of the constraints to use the safeAreaLayoutGuide of the view
// you wouldn't want your sliders to go out of the safe area, would you?
NSLayoutConstraint.activate([
rectangleB.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
rectangleB.leadingAnchor.constraint(equalTo: view.leadingAnchor),
rectangleB.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.05),
rectangleB.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/4),
saveB.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
saveB.leadingAnchor.constraint(equalTo: rectangleB.trailingAnchor),
saveB.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.05),
saveB.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/4),
libaryB.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
libaryB.leadingAnchor.constraint(equalTo: saveB.trailingAnchor),
libaryB.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.05),
libaryB.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/4),
clearB.bottomAnchor.constraint(equalTo: rectangleB.topAnchor),
clearB.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.05),
clearB.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.widthAnchor, multiplier: 1/3),
clearB.leadingAnchor.constraint(equalTo: view.trailingAnchor),
])
rectangleB.addTarget(self, action: #selector(rectangleBox), for: .touchDown)
rectangleB.setTitle("Rectangle", for: .normal)
clearB.setTitle("Clear", for: .normal)
clearB.addTarget(self, action: #selector(clearM), for: .touchDown)
saveB.addTarget(self, action: #selector(saveM), for: .touchDown)
}
@objc func saveM() {
saver()
clearM()
}
@objc func clearM() {
// Loop through all the subviews in arrTextFields and remove them from the superview
for subview in arrTextFields {
subview.removeFromSuperview()
}
// Clear the array since all views have been removed
arrTextFields.removeAll()
// Optionally, clear the currentView reference as well
currentView = nil
}
@objc func rectangleBox() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
arrTextFields.append(subview)
view.addSubview(subview)
subview.frame = CGRect(x: view.bounds.midX, y: view.bounds.midY + CGFloat(ww), width: CGFloat(ww), height: 35)
subview.backgroundColor = UIColor.orange
// Add a border to the subview
subview.layer.borderWidth = 2.0 // Set the border width
subview.layer.borderColor = UIColor.black.cgColor // Set the border color
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePanGestured(_:)))
subview.addGestureRecognizer(pan)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
// Automatically select the new rectangle
currentView = subview
}
@objc func sxBTN(sender: UISlider) {
guard let currentView = currentView else { return }
let newWidth = CGFloat(ww) * CGFloat(sender.value)
// let fixedHeight = CGFloat(35) // Keep the height fixed
let currentHeight = currentView.bounds.height // Use the already set width, keep it fixed
currentView.bounds.size = CGSize(width: newWidth, height: currentHeight)
// Bottom label for width measurement
let bottomLabel: UILabel
if currentView.subviews.count > 0, let label = currentView.subviews[0] as? UILabel {
bottomLabel = label
} else {
bottomLabel = UILabel()
currentView.addSubview(bottomLabel)
}
// Left label for height measurement
let leftLabel: UILabel
if currentView.subviews.count > 1, let label = currentView.subviews[1] as? UILabel {
leftLabel = label
} else {
leftLabel = UILabel()
currentView.addSubview(leftLabel)
}
// Mapping from width to a scale of 1 to 25
let minScale: CGFloat = 1
let maxScale: CGFloat = 25
// Calculate the scale for width
let widthScale = minScale + (newWidth / view.bounds.width) * (maxScale - minScale)
// Update label text for width
bottomLabel.text = "\(Int(widthScale))" // Bottom label measures width
leftLabel.text = "\(Int(currentHeight))" // Left label always shows the fixed height
bottomLabel.textAlignment = .center
leftLabel.textAlignment = .center
// Set label sizes (ensure they have a minimum width and height)
let labelWidth: CGFloat = 50
let labelHeight: CGFloat = 20
// Reposition the bottom label to be at the bottom center, measuring width
bottomLabel.frame = CGRect(
x: (newWidth - labelWidth) / 2, // Center horizontally
y: currentHeight - labelHeight, // Align at the bottom
width: labelWidth,
height: labelHeight
)
// Reposition the left label to be at the left center, measuring height
leftLabel.frame = CGRect(
x: 0, // Align to the left edge
y: ( currentHeight - labelHeight) / 2, // Center vertically
width: labelWidth,
height: labelHeight
)
}
@objc func handleTapGestured(_ gesture: UITapGestureRecognizer) {
currentView = gesture.view
// Set slider value to match the size of the selected box
}
@objc func handlePanGestured(_ gesture: UIPanGestureRecognizer) {
let draggedView = gesture.view!
view.bringSubviewToFront(draggedView)
let translation = gesture.translation(in: view)
draggedView.center = CGPoint(x: draggedView.center.x + translation.x, y: draggedView.center.y + translation.y)
gesture.setTranslation(.zero, in: view)
currentView = gesture.view
}
func createToolbar() -> UIToolbar {
let toolbar = UIToolbar()
toolbar.sizeToFit()
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonTapped))
toolbar.items = [flexSpace, doneButton]
return toolbar
}
@objc func doneButtonTapped() {
view.endEditing(true)
}
func saver() {
let vex = self.view.screenshot(for: view.frame, clipToBounds: true, with: UIImage(named: "")).pngData()
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Item", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Item")
if let data = vex{
item.setValue(data, forKey: "image")
print(data)
}
do {
let result = try? managedContext.fetch(fetch) as? [Item]
print("Queen",result?.count)
try? managedContext.save()
}
catch {
print("Could not save")
}
}
@objc func libraryBtn() {
let vc = twoViewController()
vc.modalPresentationStyle = .overCurrentContext // actually .fullScreen would be better
self.present(vc, animated: true)
}
}
extension UIView {
/// Takes a screenshot of a UIView, with an option to clip to view bounds and place a waterwark image
/// - Parameter rect: offset and size of the screenshot to take
/// - Parameter clipToBounds: Bool to check where self.bounds and rect intersect and adjust size so there is no empty space
/// - Parameter watermark: UIImage of the watermark to place on top
func screenshot(for rect: CGRect, clipToBounds: Bool = true, with watermark: UIImage? = nil) → UIImage {
var imageRect = rect
if clipToBounds {
imageRect = bounds.intersection(rect)
}
return UIGraphicsImageRenderer(bounds: imageRect).image { _ in
drawHierarchy(in: CGRect(origin: .zero, size: bounds.size), afterScreenUpdates: true)
watermark?.draw(in: CGRect(x: 0, y: 0, width: 32, height: 32))
}
}
}
class twoViewController: UIViewController {
var itemName : [Item] =
fileprivate let collectionView:UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
let cv = UICollectionView(frame: CGRect(x: 0, y: 0, width: 0, height: 0), collectionViewLayout: layout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.register(CustomCell.self, forCellWithReuseIdentifier: "cell")
cv.isScrollEnabled = true
return cv
}()
var backButton = UIButton()
@objc func moveLeft() {
let vcx = ViewController()
vcx.modalPresentationStyle = .overCurrentContext // actually .fullScreen would be better
self.present(vcx, animated: true)}
func loadData() {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let fetch = NSFetchRequest<Item>(entityName: "Item")
do {
self.itemName = try managedContext.fetch(fetch)
}
catch {
print("Could not load. \(error)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
// setupCollection()
loadData()
view.backgroundColor = UIColor.systemPurple
view.addSubview(collectionView)
backButton.translatesAutoresizingMaskIntoConstraints = false
backButton.backgroundColor = UIColor.systemGray
backButton.setTitle("back", for: .normal)
view.backgroundColor = UIColor.lightGray
collectionView.backgroundColor = .white
collectionView.delegate = self
collectionView.dataSource = self
//
collectionView.reloadData()
view.addSubview(backButton)
backButton.addTarget(self, action: #selector(moveLeft), for: .touchUpInside)
NSLayoutConstraint.activate ([
collectionView.topAnchor.constraint(equalTo: view.topAnchor),
collectionView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.9, constant: 0),
collectionView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1, constant: 0),
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
backButton.topAnchor.constraint(equalTo: collectionView.bottomAnchor),
backButton.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1, constant: 0),
backButton.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1, constant: 0),
backButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
])
}
let colors: [UIColor] = [.systemRed, .systemGreen, .systemBlue, .systemYellow, .systemPurple]
}
extension twoViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) → UIEdgeInsets {
return UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let padding: CGFloat = 10
let collectionViewWidth = collectionView.frame.width - padding
let itemWidth = collectionViewWidth / 2 // Adjust the divisor for larger or smaller cells
let itemHeight = itemWidth * 1.2 // Height can be proportional to width for a balanced look
return CGSize(width: itemWidth, height: itemHeight)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return itemName.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomCell
let title = itemName[indexPath.row]
let attr1 = title.value(forKey: "atBATS") as? String
let text = [" ", attr1].compactMap { $0 }.reduce("", +)
if let imageData = itemName[indexPath.row].image {
let coredataLoadedimage = UIImage(data: imageData)
cell.ii.image = coredataLoadedimage
}
cell.parentVC = self
cell.tt.text = text
// Cycle through colors based on index
cell.backgroundColor = colors[indexPath.row % colors.count]
cell.bt2.tag = indexPath.row
cell.bt2.addTarget(self, action: #selector(elete), for: .touchUpInside)
return cell
}
@objc func elete(_ sender:UIButton){
let note = itemName[sender.tag]
let managedContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
managedContext.delete(note)
do {
try managedContext.save()
collectionView.reloadData()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
class CustomCell: UICollectionViewCell {
var parentVC: UIViewController!
var bg: UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.layer.cornerRadius = 0
return iv
}()
var bt: UIButton = {
let bt = UIButton()
bt.translatesAutoresizingMaskIntoConstraints = false
bt.contentMode = .scaleAspectFill
bt.clipsToBounds = true
bt.layer.cornerRadius = 0
return bt
}()
var bt2: UIButton = {
let bt2 = UIButton()
bt2.translatesAutoresizingMaskIntoConstraints = false
bt2.contentMode = .scaleAspectFill
bt2.clipsToBounds = true
bt2.layer.cornerRadius = 0
return bt2
}()
var tt: UILabel = {
let tt = UILabel()
tt.translatesAutoresizingMaskIntoConstraints = false
tt.contentMode = .scaleAspectFill
tt.clipsToBounds = true
return tt
}()
var ii: UIImageView = {
let ii = UIImageView()
ii.translatesAutoresizingMaskIntoConstraints = false
ii.contentMode = .scaleAspectFill
ii.clipsToBounds = true
return ii
}()
override init(frame: CGRect) {
super.init(frame: .zero)
[bt2, bt, ii, tt].forEach({
$0.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview($0)
})
bt.backgroundColor = UIColor.systemPink
bt2.backgroundColor = UIColor.orange
bt.setTitle("Show", for: .normal)
bt2.setTitle("Delete", for: .normal)
ii.backgroundColor = UIColor.systemGray
tt.textAlignment = .center
// Set up the layout constraints for image, label, and buttons
NSLayoutConstraint.activate([
ii.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
ii.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
ii.widthAnchor.constraint(equalToConstant: 100),
ii.heightAnchor.constraint(equalToConstant: 100),
tt.topAnchor.constraint(equalTo: ii.bottomAnchor, constant: 10),
tt.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
tt.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.9),
tt.heightAnchor.constraint(equalToConstant: 40),
bt.topAnchor.constraint(equalTo: tt.bottomAnchor, constant: 10),
bt.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
bt.widthAnchor.constraint(equalToConstant: 60),
bt.heightAnchor.constraint(equalToConstant: 30),
bt2.topAnchor.constraint(equalTo: tt.bottomAnchor, constant: 10),
bt2.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
bt2.widthAnchor.constraint(equalToConstant: 60),
bt2.heightAnchor.constraint(equalToConstant: 30)
])
bt.addTarget(self, action: #selector(moveRight), for: .touchUpInside)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func moveRight() {
let vce = fullScreen()
vce.text = tt.text!
vce.newImage = ii.image!
vce.modalPresentationStyle = .overCurrentContext // .fullScreen can be used
parentVC.present(vce, animated: true)
}
}
class fullScreen : UIViewController{
var i = UIImageView()
var l = UILabel()
var back = UIButton()
var newImage: UIImage!
var text:String = “”
var counter = 0
var oldCons = NSLayoutConstraint
var nw = NSLayoutConstraint
override func viewDidLoad() {
l.text = text
i.image = newImage
back.setTitle(“back”, for: .normal)
l.textAlignment = .center
view.addSubview(i)
i.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(l)
l.translatesAutoresizingMaskIntoConstraints = false
back.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(back)
view.backgroundColor = UIColor.white
l.backgroundColor = UIColor.systemGray
i.backgroundColor = UIColor.systemBlue
back.backgroundColor = UIColor.orange
i.isUserInteractionEnabled = true
oldCons = [
i.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :150), i.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :150),
i.topAnchor.constraint(equalTo: view.centerYAnchor, constant : -200),
i.widthAnchor.constraint(equalToConstant: 300),
i.heightAnchor.constraint(equalToConstant: 450),
]
NSLayoutConstraint.activate(oldCons)
NSLayoutConstraint.activate ([
back.leadingAnchor.constraint(equalTo: view.leadingAnchor),
back.bottomAnchor.constraint(equalTo: view.bottomAnchor),
back.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: 1.0),
back.heightAnchor.constraint(equalToConstant: 50),
l.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :75),
l.topAnchor.constraint(equalTo: view.centerYAnchor, constant : -260),
l.widthAnchor.constraint(equalToConstant: 150),
l.heightAnchor.constraint(equalToConstant: 50),
])
let tg = UITapGestureRecognizer(target: self, action: #selector(self.selena))
i.addGestureRecognizer(tg)
back.addTarget(self, action: #selector(moveRight), for: .touchUpInside)
}
@objc func selena(){
if counter % 2 == 0 {
NSLayoutConstraint.deactivate(oldCons)
nw = [
i.leftAnchor.constraint(equalTo: view.leftAnchor),
i.rightAnchor.constraint(equalTo: view.rightAnchor),
i.topAnchor.constraint(equalTo: view.topAnchor),
i.bottomAnchor.constraint(equalTo: view.bottomAnchor)
]
NSLayoutConstraint.activate(nw)
l.isHidden = true
back.isHidden = true
print("hello")
}else{
NSLayoutConstraint.deactivate(nw)
nw = [
i.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :150), i.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :150),
i.topAnchor.constraint(equalTo: view.centerYAnchor, constant : -200),
i.widthAnchor.constraint(equalToConstant: 300),
i.heightAnchor.constraint(equalToConstant: 450),
]
NSLayoutConstraint.activate(nw)
l.isHidden = false
back.isHidden = false
print("dissy")
}
counter += 1
}
@objc func moveRight() {
let vc = twoViewController()
vc.modalPresentationStyle = .overCurrentContext // actually .fullScreen would be better
self.present(vc, animated: true)
}
var inital : Item?
@objc func backF() {
// Take a screenshot of the draw view
guard let imageData = self.view.screenshot(for: view.frame, clipToBounds: true).pngData() else {
// Handle the case where screenshot or PNG data is nil
return
}
// Ensure there is an 'Inital' object
guard let budget = inital else {
return
}
// Save the changes to Core Data
DataManger.shared.saveContext()
// Dismiss the current view controller
dismiss(animated: true)
}
}