前段時間看到QQ羣裏面有朋友問一組圖片的3D旋轉效果怎麼作,雖然以前看到過flash版本的這種效果,可是本身卻也沒有作過這種效果。因而,就想來練習練習,最終的效果是這樣的:ide
其實,這個東西就是要利用橢圓的標準方程,而後,你經過一個dispatchertimer 每隔一段時間觸發一次動做,使得裏面的圖片沿着橢圓的軌跡改變座標點,另外能夠再改變圖片的大小和透明度,使得效果看起來更好點。函數
關於橢圓及其標準方程:spa
還有一個須要用到的橢圓的性質是,知道橢圓的兩個半軸,根據角度求得在橢圓軌跡上的座標點:code
也就是橢圓的參數方程:orm
其中的角度是離心角:視頻
具有了這些幾何知識,接下來的應該很簡單了,無非就是利用silverlight中的屬性,變幻效果等等,使得每隔必定時間,讓你的圖片在如上圖那樣的橢圓軌跡上運動。好了,分析完畢,開始寫代碼:blog
首先,在xaml文件中以下寫:圖片
<
Canvas
x:Name
="MainCanvas"
Background
="Black"
>
</
Canvas
>
是否是很簡單,由於此次把大多數的操做,包括圖片的加載都放到隱藏代碼中了,這裏並無鄙視xaml的意思,其實我很喜歡xaml聲明式的代碼,可是標記代碼和後臺的邏輯代碼都是必不可少的,這也是silverlight和WPF的一大特點。只是,此次用到的邏輯比較多,在xmal中去作就不太合適。好了,接下來,看下代碼隱藏文件中是怎麼回事:ci
首先在MainPage控件類中定義這麼些私有變量:flash
private
double
_speed;
//
圖片移動速度
private
List
<
double
>
_angles;
//
離心角角度集合
private
const
double
_MAX_SPEED
=
0.009
;
//
定義的最大速度值
private
DispatcherTimer _disp;
//
定時器
private
List
<
ScaleTransform
>
scaleTransforms
=
new
List
<
ScaleTransform
>
();
//
縮放變換集合
而後,咱們須要一個初始化的函數,包括加載圖片啊,設置圖片大小,初始離心角角度集合的初始化
代碼
public
void
InitContainer()
{
_angles
=
new
List
<
double
>
();
_speed
=
_MAX_SPEED;
_disp
=
new
DispatcherTimer();
_disp.Interval
=
TimeSpan.FromMilliseconds(
25
);
//
每隔25毫秒,圖片移動一次
_disp.Tick
+=
new
EventHandler(_disp_Tick);
for
(var i
=
0
; i
<
6
; i
++
)
{
Canvas ca
=
new
Canvas();
BitmapImage bit
=
new
BitmapImage(
new
Uri(
@"
Images/
"
+
(i
+
1
)
+
"
.jpg
"
,UriKind.Relative));
Image img
=
new
Image();
img.Width
=
200
;
img.Height
=
250
;
img.Source
=
bit;
ca.Width
=
200
;
ca.Height
=
250
;
//
ca.Background = new SolidColorBrush(Colors.Red);
ca.Children.Add(img);
_angles.Add ( (Math.PI
*
2
/
6
)
*
i);
ScaleTransform sc
=
new
ScaleTransform();
scaleTransforms.Add(sc);
sc.ScaleX
=
1
;
sc.ScaleY
=
1
;
sc.CenterX
=
100
;
sc.CenterY
=
125
;
ca.RenderTransform
=
sc;
MainCanvas.Children.Add(ca);
}
_disp.Start();
}
而後再寫一個移動圖片的函數,主要功能:根據離心角的角度經過橢圓參數方程計算出此刻圖片位於橢圓軌跡上的座標點,而後再進行圖片縮放,透明度改變等效果
public
void
SetMove()
{
double
RadiusX
=
300
;
//
設定橢圓的長半軸
double
RadiusY
=
80
;
//
設定橢圓的短半軸
double
CenterX
=
550
;
//
設定圖片組的中心
double
CenterY
=
220
;
//
設定圖片組的中心
Canvas aCanvas;
for
(
int
i
=
0
; i
<
6
; i
++
)
{
aCanvas
=
MainCanvas.Children[i]
as
Canvas;
double
NewX
=
Math.Cos(_angles[i])
*
RadiusX
+
CenterX;
//
計算x座標
double
NewY
=
Math.Sin(_angles[i])
*
RadiusY
+
CenterY;
//
計算y座標
aCanvas.SetValue(Canvas.LeftProperty, NewX);
//
對圖片集合中的每張圖片進行從新定位
aCanvas.SetValue(Canvas.TopProperty, NewY);
_angles[i]
+=
_speed;
//
根據速度改變離心角的角度
aCanvas.SetValue(Canvas.ZIndexProperty, System.Convert.ToInt32(NewY));
//
設置圖片的zIndex屬性,防止位於底層的圖片遮擋上層的圖片
double
opacity
=
Math.Sin(_angles[i])
+
1.5
;
//
改變圖片透明度,其實這裏是改變畫布透明度
aCanvas.SetValue(Canvas.OpacityProperty, opacity);
var curr
=
scaleTransforms[i];
var change
=
NewY
/
(CenterY
+
RadiusY
-
curr.ScaleY);
//
從新計算畫布大小
curr.ScaleX
=
change;
curr.ScaleY
=
change;
}
}
最後,把SetMove()函數放到dispatchertimer的tick觸發函數中,每隔25ms 調用,更新每張圖片的位置和大小及其透明度
void
_disp_Tick(
object
sender, EventArgs e)
{
SetMove();
}
這樣一個旋轉圖片組的效果就作好了 :)
總結:此次其實沒有直接去控制圖片的位置,而是把圖片放到畫布中,經過改變畫布的位置而改變圖片的位置,這樣作的好處是,可複用性更強一些,之後不僅是作圖片,能夠把文本,按鈕,或者其它控件甚至視頻放到其中,產生這樣的效果。固然,更好的作法是本身把它封裝成控件,以便之後更方便使用,另外,這個效果目前仍是比較基礎和粗糙的,還有不少地方能夠改進,例如,能夠加入鼠標的交互,當鼠標移到上面不一樣位置產生加速,減速,改變方向,改變橢圓中心等等~