unity ugui縮放 移動

2022-02-26 15:21:47 字數 4948 閱讀 5241

乾貨羅列在前,不願意看的,拿東西走人,自己研究:

關於ugui的排版方面,剛上手的時候,覺得:哎喲!不錯,這個刁。

但是如果你使用過qt等軟體,其實ugui的對齊功能還是很落後的。

如果你繼續使用這個排版功能,你就會發現:什麼啊這是,什麼邏輯啊,完全沒懂啊。

如何修改ugui控制項到我指定的大小

如何移動ugui到指定位置上去

關於ugui的以上兩點,都在recttransform這個元件裡。而這個元件的變數雖然並不很多,但是互相關聯非常精密。如果沒有弄懂ugui是如何設計的,幾乎沒辦法隨心所欲的工作。

這裡說的隨心所欲的工作指的是:當我想要移動或者縮放ugui控制項的時候,能夠直接修改變數成我期望的值,或者傳入引數就能達到我期望的效果。

比方說。我期望控制項移動到跟另外乙個控制項相同的位置上去(對齊)。或者我希望a控制項改變大小和b一樣。又或者跟隨滑鼠移動。

以上三個情況,如果你擺弄過ugui,其實就很容易暴露recttransform裡面的問題。

以下,用我的工作作為講解。告訴你如何通過簡單的技巧,讓你跳過理解ugui排版直接實現最簡單的移動和縮放。讓排版功能化繁為簡,返璞歸真

先說一些基本的內容。

position和localposition值不一樣,而且沒有找出規律,在我測試到的範圍內,position這個變數幾乎不能用於指令碼的各種計算。

ugui在控制項位置不發生變化的情況下,修改pivot,position和localposition會變。

pivot這個變數,在unity面板裡修改和在指令碼裡修改表現出的行為不一致。在unity面板裡修改,表現出的行為是ugui空間在螢幕上的位置沒有發生變化,而position和localposition有改變;

在指令碼裡修改pivot,position和localposition不會改變,而ugui空間在螢幕上的位置會改變

rect唯讀,整個結構下面的所有資料僅僅是唯讀,沒找到方法修改。但是rect的widht和height屬性記錄的是ugui控制項的畫素大小(縮放是否參與影響暫時還沒進展到這步)

可以通過sizedelta修改ugui控制項大小。但是這個變數和ugui自身的對齊方式有關(錨點位置和方式),如果你沒有弄懂對齊方式跟sizedelta的關係,只是簡單的將sizedelta改成(100.0f,100.0f)出現的大小可能不會是100×100.

有了以上基本內容,就可以開始講解了。

我要做乙個鑲嵌。將b鑲嵌到a的slot裡去。slot有背景圖,初始很小,鑲嵌物大小不一,所以當鑲嵌完成,背景圖需要縮放。b需要修改座標和a的slot相同。

先說縮放。

會影響縮放的,主要是anchor引數。這個引數在不同值的時候,對縮放的影響是不一樣的。因為slot有上有下,有些靠左,有些靠右,有些居中,所以anchor引數各式各樣。

思路其實很簡單。因為在scanl都為1的狀態下(別的狀態還沒測試),rect的widht和height屬性就是控制項的大小。所以將b的大小直接給slot即可。

於是將sizedelta修改為widht和height的值。完成。

最開始的時候所有slot的錨點都是在左上角,該方案還行。可是後面出現了各種隨父控制項大小變化以及錨點左中右對齊的slot之後,這個方案就失效了,將b的widht和height直接給slot,出現了各種奇怪的大小。

這才發現收anchor變數和offsetmax/min這些變數影響。

除錯了很久,輸出sizedelta資訊檢視之後才發現,雖然sizedelta的值很難理解,但是sizedelta的增量卻是正確的。比方說,我將sizedelta改成100×100和200×200大小我是確定不了。但是從100到200,sizedelta的輸出資訊可以看到增量了100。

於是逐將上面的方案改為:

sizedelta+增量即可。

**片段

1         recttransform mnewnoderect = newnode.getcomponent();

2 recttransform mslotrect = mslot.getcomponent();

3float mx = mnewnoderect.rect.width -mslotrect.rect.width;

4float my = mnewnoderect.rect.height -mslotrect.rect.height;

5 mslotrect.sizedelta = new vector2(mslotrect.sizedelta.x + mx, mslotrect.sizedelta.y + my);

至此,縮放搞定。你不需要知道任何ugui對齊相關的東西,就可以實現準確的縮放。

然後是移動。

最開始做的時候,因為錨點全都在左上角。所以移動的時候很簡單,直接在面板裡修改posx和posy就好。

但是因為posx和posy受pivot影響,所以輸出檢視座標資料,發現position和localposition兩個變數,localposition變數的值是posx和posy裡的資料,於是採用了localposition。

於是鑲嵌方案就是:

先將slot拉到b的大小,然後再將slot的位置給b。

因為從外部保證了介面製作的時候,錨點和pivot全部一樣,所以這個方案成功用了一段時間。

後來,隨著各種其他方式的錨點的加入,又有不同的pivot的加入。原本的座標直接給值的方案就不行了。於是又測試。

這次測試發現,ui控制項座標,是以pivot點為原點。如果你將兩個不同對齊方式的ugui控制項設定成一樣的localposition(父控制項相同的前提下),那麼對齊的點,是pivot點。

因為我的slot背景圖已經拉伸到和b一樣大了。所以我需要的是讓兩個控制項的左上對齊。

而pivot是乙個0~1的值。0,就在最左上,1就在右下。正好是寬高。所以widht*pivot.x正好就是左邊到pivot的距離。

於是修改方案就出來了。

1         vector3 mlefttop =m_rect.localposition;

2float mleftoffset = m_rect.rect.width *m_rect.pivot.x;

3float mtopoffset = m_rect.rect.height *m_rect.pivot.y;

4 mlefttop.x -=mleftoffset;

5 mlefttop.y -=mtopoffset;

67 recttransform minsert = m_insert.getcomponent();

8 mleftoffset = minsert.rect.width *minsert.pivot.x;

9 mtopoffset = minsert.rect.height *minsert.pivot.y;

10 vector3 mfinalypos = mlefttop + new vector3(mleftoffset, mtopoffset, 0.0f

);11 minsert.localposition = mfinalypos;

原理就是,先計算出slot的左上角的點。然後再將b設定到這個點上,然後b再自己加上從左上點到pivot點的差值。就可以讓兩圖以左上角對齊了(其他對齊方式自行推演)。

乙個sizedelta,乙個localposition就可以跳過複雜的ugui的錨定實現正確的對齊和縮放。

至此,ugui的縮放和移動就大功告成。

這裡不得不談下自己的感想:

我們做東西的時候,都是習慣先按照自己的思維和理解來做。如果符合自己的思維,則好用。不符合,「這tm什麼設計,腦子有屎」。用這樣的觀點來做事,不太好。一是不尊重別人的勞動成果。二是學習東西始終帶牴觸情緒。

雖然我知道我應該去學習和滿足unity的設計要求。但是這樣的ugui設計,真的是腦子有屎。強大到只有程式才會懂的ui,你做鳥的編輯介面啊。直接給程式說明文件就好了。想做個ui上最常見的移動和縮放,我還得先研究一下ui系統怎麼設計的。而且最終出來的效果是既不方便使用,也不方便理解,也趕不上別的ui系統(有用過qt做程式設計的就會懂得qt的編輯器和ui對齊方式多麼直觀)。我只想說:這tm什麼設計,腦子有屎。

這個ugui,一點都不符合unity的風格。

特別補充一點,以上方案,是在a是父物件,slot和b同級目錄下,scan為1的情況下進行的,不同目錄情況,請自信根據文中線索推導。另外縮放係數參與的情況下未進行測試

------------------------2016 09 26 11:33--------------------------

在已經有以上知識內容的前提下,修正乙個bug。

因為pivot這個變數是用於鉚釘控制項自身的對齊方式。舉例:如果我把座標填寫成0.0.0點。空間將會用pivot的點去對。而pivot是以左下角為0.0,所以如果pivot為0.0的時候,你會看到控制項以左下角為對齊點去對0.0.0點座標。

提這個的原因是因為,獲取到a的座標之後,其實是獲取的a的pivot點。需要通過修正來滿足自己的需求。本文上面的

float mleftoffset = m_rect.rect.width *m_rect.pivot.x;

float mtopoffset = m_rect.rect.height *m_rect.pivot.y;

mlefttop.x -=mleftoffset;

mlefttop.y -=mtopoffset;

這段修正**,是在計算左下點的座標,而不是左上。

提到這裡我覺得就夠了,座標點算偏移不是難事,各位自己算下自己期望的座標偏移就好。我也要自己檢查下為什麼之前用這個演算法算出來竟然是期望的左上。

------------------------2016 09 26 19:01--------------------------

好吧,我查了下我自己的bug,我這個演算法,其實是左下角對齊的方式。但是呢,因為我的鑲嵌背景和鑲嵌物等大,所以鑲嵌上去之後,左下對齊和左上對齊就沒有任何差別。

如果是不等大的座標排列,可以自己計算一下高度差,或加或減一下就好了。

WPF 實現縮放移動

熟悉wpf 的朋友應該知道canvas 預設是不支援scale 和offset 操作的,如果我們想對canvas 裡包含的控制項進行整體縮放或移動可能會比較麻煩。kael rowan 提供了zoomablecanvas 類可以方便實現上述效果。我們可以在xaml 中直接使用對控制項布局進行開發,而不...

WPF 實現縮放移動

熟悉wpf 的朋友應該知道canvas 預設是不支援scale 和offset 操作的,如果我們想對canvas 裡包含的控制項進行整體縮放或移動可能會比較麻煩。kael rowan 提供了zoomablecanvas 類可以方便實現上述效果。我們可以在xaml 中直接使用對控制項布局進行開發,而不...

移動端背景縮放

background size 500px 200px 2 只寫乙個引數時為寬度,高度省略會等比例縮放 background size 500px 3 單位可以跟百分百 相對于父盒子來說的 background size 50 4 cover屬性 要完全覆蓋div盒子,等比例拉伸,可能有部分顯示不全...