【问题标题】:Pinning a UIButton to a specific location on a photograph将 UIButton 固定到照片上的特定位置
【发布时间】:2020-07-09 17:03:25
【问题描述】:

urbanPan

你好,

我有一张顶部带有 UI 按钮的照片。 UI 按钮需要位于照片上非常具体和精确的位置。

当我调整照片大小时(例如,针对不同的设备),UI 按钮永远不会保持对齐。

容器不起作用,因为它们与屏幕尺寸和方向有关,而不是与照片的纵横比和尺寸有关。

例如,当照片在 iPad 等较大设备上未裁剪时,容器规则不再相关。

固定不起作用,因为绝对值无法按比例放大和调整大小。

我知道我想要实现的目标是可能的,因为它在其他应用中很常见且可见。但是,Xcode 中的对齐和约束似乎并没有为此提供便利?

我确定我错过了什么。任何想法,非常感谢。

请参阅下面的 urbanPan 图片或 urbanPan.io 获取 Github 文件。

urbanPan

祝福, 城市粉碎

虽然问题似乎与 Main.Storyboard 布局更直接相关,但这里是 ViewController.swift 的代码

//
//  ViewController.swift
//  urbanPan
//
//  Created by URBANSMASH pro on 29/08/2019.
//  Copyright © 2019 Play it on Pan. All rights reserved.
//

import UIKit
import AVFoundation
import AudioKit

class ViewController: UIViewController, AVAudioPlayerDelegate {

    var player : AVAudioPlayer!

    let sounds = ["Rest", "2-F3", "2-FS3", "2-G3", "2-GS3", "2-A3", "2-AS3", "2-B3", "2-C4", "2-CS4", "2-D4", "2-DS4", "2-E4", "2-F4", "2-FS4", "2-G4", "2-GS4", "2-A4", "2-AS4", "2-B4", "2-C5", "2-CS5", "2-D5", "2-DS5", "2-E5", "2-F5", "2-FS5", "2-G5", "2-GS5", "2-A5", "2-AS5", "2-B5", "2-C6"]

    var noteNum = 0

    let conductor = Conductor.shared
    var isPlaying = false
    var currentSound = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        conductor.midi.addListener(self)
        conductor.loadSamples(byIndex: currentSound)
    }


    @IBAction func noteReleased(_ sender: UIButton) {
        noteNum = sender.tag
//        player.currentTime = 0
        stopSound()

    }

    @IBAction func notePlayed(_ sender: UIButton) {
        noteNum = sender.tag
        //        player.currentTime = 0
        playSound()

    }

    func stopSound() {

        noteOff(note: MIDINoteNumber(noteNum))

    }

    func playSound() {

        noteOn(note: MIDINoteNumber(noteNum))

    }

    func noteOn(note: MIDINoteNumber) {
        DispatchQueue.main.async {
            self.conductor.playNote(note: note, velocity: 100, channel: 0)
        }
    }

    func noteOff(note: MIDINoteNumber) {
        DispatchQueue.main.async {
            self.conductor.stopNote(note: note, channel: 0)
        }
    }

}

extension ViewController: AKMIDIListener {

    func receivedMIDINoteOn(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel) {
        DispatchQueue.main.async {
            self.conductor.playNote(note: noteNumber, velocity: velocity, channel: channel)
        }
    }

    func receivedMIDINoteOff(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, channel: MIDIChannel) {
        DispatchQueue.main.async {
            self.conductor.stopNote(note: noteNumber, channel: channel)
        }
    }

    // MIDI Controller input
    func receivedMIDIController(_ controller: MIDIByte, value: MIDIByte, channel: MIDIChannel) {
        AKLog("Channel: \(channel + 1) controller: \(controller) value: \(value)")
        //conductor.controller(controller, value: value)
    }

    // MIDI Pitch Wheel
    func receivedMIDIPitchWheel(_ pitchWheelValue: MIDIWord, channel: MIDIChannel) {
        //conductor.pitchBend(pitchWheelValue)
    }

    // After touch
    func receivedMIDIAfterTouch(_ pressure: MIDIByte, channel: MIDIChannel) {
        conductor.afterTouch(pressure)
    }

    func receivedMIDISystemCommand(_ data: [MIDIByte]) {
        // do nothing: silence superclass's log chatter
    }

    // MIDI Setup Change
    func receivedMIDISetupChange() {
        AKLog("midi setup change, midi.inputNames: \(conductor.midi.inputNames)")
        let inputNames = conductor.midi.inputNames
        inputNames.forEach { inputName in
            conductor.midi.openInput(name: inputName)
        }
    }

    func setSpeakersAsDefaultAudioOutput() {
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
        }
        catch {
            // hard to imagine how we'll get this exception
            let alertController = UIAlertController(title: "Speaker Problem", message: "You may be able to hear sound using headphones.", preferredStyle: UIAlertController.Style.alert)
            let okAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.default) {
                (result: UIAlertAction) -> Void in
            }

            alertController.addAction(okAction)
            self.present(alertController, animated: true, completion: nil)
        }
    }



}

【问题讨论】:

  • 要获得答案,您需要包含清楚描述问题的代码。
  • 按照建议添加代码。另请参阅显示 Main.Storyboard 布局的图像 urbanPan。

标签: swift xcode uibutton alignment constraints


【解决方案1】:

对于这种布局,我认为 FrameLayout 优于 AutoLayout。 当调用 viewDidLayoutSubviews 方法时,根据屏幕大小计算并更新视图大小和位置。

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        let screenSize = UIScreen.main.bounds
        // ... 
        d4View.frame = ...
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-15
    • 1970-01-01
    相关资源
    最近更新 更多