2016-06-07 110 views
2

我想動態調整UIView的框架。我可以更新代碼中的框架並查看值已更改,但實際顯示不會更改,即使我運行setNeedsDisplay()。Swift:更改UIView框架但顯示不更新

我跟隨this post,我通過CGRectMake定義了一個新框架,然後將UIView的框架設置爲這個新框架。即我正在這樣做......

let newFrame = CGRectMake(minX,minY, width, height) 
VUBarCover.frame = newFrame 

如果我打印出UIView的幀的值,我看到它正在改變,因爲我喜歡。但顯示器(在模擬器中)從不反映這些變化。

任何想法如何解決這個問題?

更新:更詳細:我試圖以編程方式掩蓋與另一個UIView。這是一個水平的「VU Meter」,由一個基本的UIImageView組成,顯示一個顏色漸變,部分動態地被黑色背景的UIView「覆蓋」。 UIImageView「VUBarImageView」在StoryBoard中定義,並受AutoLayout控制。黑色UIView「VUBarCover」純粹是以編程方式定義的,沒有AutoLayout約束。

下面是完整的代碼的相關部分......我遇到的麻煩是在updateVUMeter()...

@IBOutlet weak var VUBarImageView: UIImageView! 
var VUBarCover : UIView! 

// this gets called after AutoLayout is finished 
    override func viewDidLayoutSubviews() { 
     // cover up VU Meter completely 
     let center = VUBarImageView.center 
     let width = VUBarImageView.frame.width 
     let height = VUBarImageView.frame.height 
     let frame = VUBarImageView.frame 
     VUBarCover = UIView(frame: frame) 
     MainView.addSubview(VUBarCover) 
     VUBarCover.backgroundColor = UIColor.blueColor() // use black eventually. blue lets us see it for testing 
    } 

// partially cover up VUBarImage with black VUBarCover coming from the "right" 
func updateVUMeter(inputValue:Float) { //inputValue is in dB 

    //let val = pow(10.0,inputValue/10) // convert from dB 
    let val = Float(Double(arc4random())/Double(UInt32.max)) //for Simulator testing, just use random numbers between 0 and 1 
    print("val = ",val) 

    let fullWidth = VUBarImageView.frame.width 
    let maxX = VUBarImageView.frame.maxX 
    let width = fullWidth * CGFloat(1.0-val) 
    let minX = maxX - width 
    let minY = VUBarImageView.frame.minY 
    let height = VUBarImageView.frame.height 

    let newFrame = CGRectMake(minX,minY, width, height) 
    VUBarCover.frame = newFrame 
    VUBarCover.setNeedsDisplay() 

    print("fullWidth = ",fullWidth,"width = ",width) 
    print(" newFrame = ",newFrame,"VUBarCover.frame = ",VUBarCover.frame) 
} 

和實例的結果是:

val = 0.9177 
fullWidth = 285.0 width = 23.4556210041046 
newFrame = (278.544378995895, 93.5, 23.4556210041046, 10.0) VUBarCover.frame = (278.544378995895, 93.5, 23.4556210041046, 10.0) 
val = 0.878985 
fullWidth = 285.0 width = 34.4891595840454 
newFrame = (267.510840415955, 93.5, 34.4891595840454, 10.0) VUBarCover.frame = (267.510840415955, 93.5, 34.4891595840454, 10.0) 
val = 0.955011 
fullWidth = 285.0 width = 12.8218790888786 
newFrame = (289.178120911121, 93.5, 12.8218790888786, 10.0) VUBarCover.frame = (289.178120911121, 93.5, 12.8218790888786, 10.0) 

。 ..ie,我們看到VUBarCover.frame正在改變'內部',但在屏幕上它永遠不會改變。我們看到的是全尺寸封面,完全覆蓋下面的圖像(約300像素寬),即使它的寬度只有12像素)。

即使我在VUBarCover的超級視圖上做了setNeedsDisplay(),也沒有任何變化。

幫助?謝謝。

回答

3

首先,你必須值得注意的幾個誤區:

  • 實例變量(如VUBarCoverMainView應該總是以小寫字母(如mainView)開始
  • 你應該在年初打電話super.viewDidLayoutSubviews()。你的覆蓋實現

其次,viewDidLayoutSubviews()可以被調用任意次數,所以你的這個方法的實現應該是idempotent,這意味着它具有相同的效果,無論它被稱爲多少次。但是,當你撥打:

VUBarCover = UIView(frame: frame) 
MainView.addSubview(VUBarCover) 

您正在創建一個新的UIView並將其添加到視圖層次,你可能在過去已添加的人相處。所以它看起來像框架沒有在屏幕上更新。事實上,你只是不能說,因爲意見後面的更新和他們沒有改變。

相反,你可能要創建一次這樣的:

var vuBarCover = UIView() 

添加它作爲一個子視圖中viewDidLoad()

mainView.addSubview(vuBarCover) 

並修改其框架viewDidLayoutSubviews()

vuBarCover.frame = vuBarImageView.frame 

您無需致電setNeedsDisplay()

+0

亞倫,謝謝你的詳細解答。忽略我的首字母大寫的全局變量的文體選擇,我已經實現了你所描述的內容,不同之處在於,現在VUBarCover在顯示器上顯示爲零寬度,即它根本不覆蓋圖像,否則同樣的問題適用:'內部'我可以看到通過打印語句改變框架,但在顯示屏上沒有任何反應。 – sh37211

+0

也許它正在被另一種觀點裁剪?您是否嘗試過使用新版本[Debug View Hierarchy](https://www.raywenderlich.com/98356/view-debugging-in-xcode-6)功能?我能想到的唯一的另一件事是,也許你從後臺線程而不是主線程調用'updateVUMeter' –

+0

後臺線程是我的假設。 @ sh37211,調用updateVUMeter的代碼是什麼? –

1

我正在製作像您這樣的自定義UIView,也許我可以提供幫助。

首先,viewDidLayoutSubviews()喜歡你的評論:在AutoLayout完成後調用它。在每個佈局設置完成之後,您就開始爲您的UIView和UIImage設置新的框架,也許錯誤在這裏。請嘗試將viewDidLayoutSubviews()中的代碼移動到layoutSubviews()。別忘了在override函數中添加super.layoutSubviews(),它可以幫助您遠離數百個錯誤:]。

其次,只有當你重寫的drawRect:方法,那麼你應該調用setNeedsDisplay(),這是告訴系統,我需要重繪我的看法,以及系統會調用drawRect:方法適當。

希望你能弄明白。