第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果

まず初めに、このプログラムで実装する機能の動作を、下記に解説しておきます。

上段に少し大きめの画像が、下段には複数の小さめの画像が配置されています(図1)。上段の画像を下段の画像の集団にドラッグ&ドロップすると、画像のサイズが、RippleEffect効果を伴って、下段内の画像のサイズと同じになります(図2)。 RippleEffectは、画像に波紋をシミュレートする効果です。上段に画像をドラッグ&ドロップした場合は、画像サイズは元の大きいサイズのままになっています。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第1张图片

図1:上段に少し大きめの画像が配置され、下段には複数の小さめの画像が配置されている(クリックで拡大)

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第2张图片

図2:上段の少し大きめの画像を、下段にドラッグ&ドロップすると、RippleEffect効果を伴って、画像サイズが同じになる(クリックで拡大)

今回のサンプルは以下よりダウンロードできます。
→ 今回のサンプルファイル(2.43MB)

新規プロジェクトの作成

早速サンプルを作っていきましょう。本稿では開発言語にVisual Basicを用います。

VS 2010のメニューから[ファイル(F)/新規作成(N)/プロジェクト(P)]を選択します。次に、「Silverlight アプリケーション」を選択して、「名前(N)」に任意のプロジェクト名を指定します。ここでは「SL4_ImageDropRipple」という名前を付けています。

ソリューションエクスプローラー内にImageというフォルダを作成して、4枚の画像も追加しておきます。ダウンロードされたサンプル・ファイルには画像は追加済みです。

コントロールの配置

要素のWidthに800、Heightに600と指定します。ツールボックスからCanvasコントロールを配置します。Widthが800、Heightが300のCanvasコントロールを2個、上下に配置します。先に下のCanvasを配置し、x:NameにTargetと指定します。次に、上にCanvasを配置し、x:NameにSourceと指定します(図3)。書き出されるコードはリスト1のようになります。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第3张图片

図3:Canvasを上下に2個配置する(クリックで拡大)

リスト1 書き出されたXAMLコード(MainPage.xaml)

01
02   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
03   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
04   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
05   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
06   mc:Ignorable="d"
07   d:DesignHeight="300" d:DesignWidth="400" Width="800" Height="600">
08   
09     
10     
11   
12

次にSourceのCanvas内にImageコントロールを1個配置します。Widthに320、Heightに240を指定し、SourceプロパティにImageフォルダ内の画像を指定します。ここでは「菜の花.jpg」を指定しています。

同様にTargetのCanvas内に3個のImageコントロールを適当な位置に配置し、SourceプロパティにImageフォルダ内の画像を指定します。この場合のImageコントロールのWidthは160、Heightは120としておきます(図4)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第4张图片

図4:2つのCanvas内にImageコントロールを配置し画像を読み込む(クリックで拡大)

書き出されるコードはリスト2のようになります。

リスト2 書き出されたXAMLコード(MainPage.xaml)

01 (1)x:NameがTargetの 要素内に3個の要素を配置しています。Widthは160、Heightは120としています。
02 (2)x:NameがSourceの要素内に1個の要素を配置しています。Widthは320、Heightは240としています。
03
04     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
05     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
06     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
07     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
08     mc:Ignorable="d"
09     d:DesignHeight="300" d:DesignWidth="400" Width="800" Height="600">
10  
11     
12      ■(1)
13         
14         
15         
16     
17      ■(2)
18         
19     
20   
21

ソリューションエクスプローラー内の、MainPage.xamlを選択し、マウスの右クリックで表示されるメニューの、「Expression Blendを開く(X)」を選択し、Blend4を起動します。

Blend4でのImageのDropShadowEffec(陰影)の設定

表示されている4枚の画像を全て選択し、プロパティの[外観]パネル内のEffectの横にある[新規作成]ボタンをクリックします。「オブジェクトの選択」画面が表示されますので、DropShadowEffectを選択します(図5)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第5张图片

図5:DropShadowEffectを選択する(クリックで拡大)

全てのImageコントロールを選択していたのを解除し、一番大きい画像のImage1を選択します。プロパティの[外観]パネル内のEffectの左に、矢印アイコンが表示されますので、これをクリックするとDropShadowEffectの各種プロパティが設定できます。BlurRadiusには影のぼかし程度の値を指定します。ここでは12を指定します。Colorには影の色を指定します。ShadowDepthにはImageと影との距離の値として、20を指定します。そのほかはデフォルトのままです(図6)。ほかの3枚のImageにも同じ値を指定します。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第6张图片

図6:DropShadowEffectのプロパティを設定する

Blendの画面上では、DropShasowEffectが適用した形では表示されませんが、Blend4のメニューの「プロジェクト(P)/プロジェクトの実行(R)」で実行すると、DropShadowEffectが適用されているのがわかります(図7)。またVS2010画面上では、DropShadowEffectが適用されて表示されます。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第7张图片

図7:DropShadowEffectが適用されている(クリックで拡大)

Canvasの背景色の設定

次に、2つのCanvasの背景色を設定します。「オブジェクトとタイムライン(B)」から、Sourceを選択し、プロパティの[ブラシ]パネルにあるBackgroundを選択します。「グラデーションブラシ」アイコンをクリックします(図8)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第8张图片

図8:Canvas(Source)の背景色に「グラデーションブラシ」を適用する

上から下に向かってグレー系統色のグラデーションがかかります。上の方が暗くなり、下に向かって明るくなっているのを逆にします。色の「エディター」内の2つのカラーストップを左右入れ替えることで、上下の明暗のグラデーションが逆になります(図9)。上の方が明るく下の方が暗いグラデーションになります。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第9张图片

図9:カラーストップを左右逆にする(クリックで拡大)

同じようにTargetのCanvasにも背景色にグラデーションを設定します。グラデーションの明暗の向きはそのままで構いません。全体に、中心が暗く外に向かって明るくなるグラデーションがかかります(図10)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第10张图片

図10:2つのCanvasの背景色にグラデーションを指定した(クリックで拡大)

状態(S)の設定

「状態(S)」パネルの「状態グループの追加」アイコンをクリックし(図11)、さらに「状態の追加」アイコンをクリックします(図12)。

「●VisualState状態 記録オン」に変わり、アートボード上の画面全体が赤の枠線で囲まれます。この状態でタイムラインの記録が可能になります。

「ImageSmall」という名前を入力します(図13)。「タイムラインを表示する」アイコンをクリックして、タイムラインを表示します(図14)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第11张图片

図11:「状態グループの追加」アイコンをクリックする

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第12张图片

図12:「状態の追加」アイコンをクリックする

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第13张图片

図13:「ImageSmall」という名前を入力する

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第14张图片

図14:タイムラインを表示する

「オブジェクトとタイムライン(B)」からImage1を選択します。黄色の再生ヘッドが0の位置で、楕円マークと+の追加された、「キーフレームの記録」アイコンをクリックします。Image1の再生ヘッドが0の位置に楕円マークが表示されます(図15)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第15张图片

図15:Image1の再生ヘッドが0の位置に楕円マークが表示された

次に再生ヘッドを0.5の位置に移動し、プロパティの[変換]パネルにある、RenderTransformの「拡大縮小」アイコンをクリックし、Xに0.5、Yに0.5と入力します。Image1の画像が縮小されます(図16)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第16张图片

図16:RenderTransformの「拡大縮小」のXに0.5、Yに0.5と指定する(クリックで拡大)

「●ImageSmall状態記録オン」の●をクリックして、タイムラインの記録をオフにします。

同様な手順で、ImageLargeという状態を追加します。タイムラインの記録をオフの状態にして、Image1を選択し、再生ヘッドが0の位置で、プロパティの[変換]パネルにあるRenderTransformの「拡大縮小」のXとYの値に0.5と入力します。

「●ImageLarge記録オフ」の●をクリックして、記録オンにします。再生ヘッドが0の位置で、「キーフレームの記録」アイコンをクリックします。再生ヘッドを0.5の位置に移動し、RenderTransformの「拡大縮小」のXとYの値に1と入力します(図17)。ここまでの手順はImage1が選択された状態で行ってください。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第17张图片

図17:ImageLargeのタイムラインを記録する。Image1のRenderTransformの「拡大縮小」のXとYに1を入力し画像が元のサイズに戻ってる(クリックで拡大)

「●ImageLarge状態記録オン」の●をクリックして、記録オフにしてください。Image1が、元のサイズの状態である、再生ヘッドが0.5の位置で記録をオフにしてください。

Ripple特殊効果の設定

Blend4の[アセット(T)]パネルをクリックし、「コントロール」からRippleを検索して表示させます。「検索」欄に「Ripp」と入力すると、Rippleが表示されます(図3)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第18张图片

図18:「検索」欄に「Ripp」と入力して、Rippleが表示された

表示されたRippleを「オブジェクトとタイムライン(B)」内のTarget要素上にドラッグ&ドロップします(図19)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第19张图片

図19:RippleをTarget上にドラッグ&ドロップした

Targetの子として追加された、RippleEffectを選択して表示されるプロパティの「名前」に、myRippleEffectと指定し、Frequencyに0、 Magnitudeに0、 Phaseに0と指定しておきます(図20)。Frequencyにはシェーダー内の周波数の値を指定します。Magnitudeにはシェーダー内の振幅の値を指定します。Phaseにはシェーダー内のフェーズ値を指定します。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第20张图片

図20:RippleEffectのプロパティを設定する

Storyboardの作成

「オブジェクトとタイムライン(B)」の下にあるストーリーボードの「新規作成」アイコン(+)をクリックし、RippleStoryboardというストーリーボードを作成します(図21)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第21张图片

図21:RippleStoryboardという名前のストーリーボードを作成する(クリックで拡大)

アートボード上の画面全体が赤の枠線で囲まれ、「●RippleStoryboardタイムライン記録オン」に変わります。この状態でタイムラインの記録が可能になります。

「タイムラインとオブジェクト(B)」内のRippleEffectを選択し、タイムラインの黄色い再生ヘッドを0秒に合わせます。RippleEffectのプロパティ「Frequency」に40と指定します。「Magnitude」には0、Phaseには0と指定します。既に0が初期値として入力されている場合も、上書きで0と入力してください。Centerの値はデフォルトの0.5のままです。

「オブジェクトとタイムライン(B)」内のRippleEffectのEffect内に、いま設定したプロパティが追加されます(図22)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第22张图片

図22:各プロパティが追加された(クリックで拡大)

次に、RippleEffectを選択した状態で、再生ヘッドを0.1秒の位置に移動し、「Frequency」に30、「Magnitude」に0.02、「Phase」に0と指定します。

次に、RippleEffectを選択した状態で、再生ヘッドを1.3秒の位置に移動し、「Frequency」に0、「Magnitude」に0、「Phase」に0と指定します。既に、0が入力されていても上書きで再入力してください。

0と上書き入力したプロパティにも、楕円のマークが追加されます(図23)。

第5回 画像のドラッグ&ドロップによるRippleEffect特殊効果_第23张图片

図23:何も指定しなかったプロパティにも楕円のマークが追加されている

ここまでの手順をまとめると、表1のようになります。

表1 RippleStoryboard

プロパティ名 再生ヘッドの位置(秒)
0 0.1 1.3
Frequency 40 30 0
Magnitude 0 0.02 0
Phase 0 0 0

「●RippleStoryboardタイムライン記録オン」の●をクリックしてオフとし、Blend4を終了してVS2010に戻ります。

ソリューションエクスプローラー内のMainPage.xamlを展開して表示されるMainPage.xaml.vbをダブルクリックしてリスト3のコードを記述します。

ロジックコードを記述する

リスト3 (MainPage.xaml.vb)

view source print ?
01 Option Strict On
02 Partial Public Class MainPage
03   Inherits UserControl
04  
05     Public Sub New()
06     InitializeComponent()
07   End Sub
08  
09 マウスの左ボタンが押されたか、離されたかを判別するブール型メンバ変数、myMouseCaptureを宣言します。
10   Dim myMouseCaputer As Boolean
11 マウスポインタのY座標を格納するメンバ変数myYPosを宣言します。
12   Dim myYPos As Double
13 マウスポインタのX座標を格納するメンバ変数myXPosを宣言します。
14   Dim myXPos As Double
15 ImageがDropされた時のY座標を格納するメンバ変数myYDropPos変数を宣言します。
16   Dim myYDropPos As Double
17  
18 ■ページが読み込まれた時の処理
19   Image1のMouseLeftButtonUpイベント時に、Image1Droppedプロシージャを実行します。
20   Image1のMouseLeftButtonDownイベント時に、Image1Largedプロシージャを実行します。
21     Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
22         AddHandler Image1.MouseLeftButtonUp, AddressOf Image1Dropped
23         AddHandler Image1.MouseLeftButtonDown, AddressOf Image1Larged
24     End Sub
25  
26 ■Image1上でマウスの左ボタンが押された時の処理
27   カーソルを手の形にします。senderオブジェクトの持っているImageの情報を、DirectCastでImage型に変換し、変数myImageで参照します。マウスポインタの左上隅にあるY座標の値をメンバ変数myYPosに格納します。マウスポインタの左上隅にあるX座標の値をメンバ変数myXPosに格納します。Image1上でマウスの左ボタンが押されたため、ブール型の変数myMouseCaptureにTrueを指定しておきます。CaptureMouseメソッドで、Image1のマウスキャプチャを有効にします。
28 Private Sub Image1_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Image1.MouseLeftButtonDown
29     Image1.Cursor = Cursors.Hand
30     Dim myImage As Image = DirectCast(sender, Image)
31     myYPos = e.GetPosition(Nothing).Y
32     myXPos = e.GetPosition(Nothing).X
33     myMouseCaputer = True
34     myImage.CaptureMouse()
35     End Sub
36  
37 ■Image1上でマウスの左ボタンが離された時の処理
38   カーソルを矢印の形にします。senderオブジェクトの持っているImageの情報を、DirectCastでImage型に変換し、変数myImageで参照します。Image1上でマウスの左ボタンが離されたため、ブール型の変数myMouseCaptureにFalseを指定しておきます。ReleaseMouseCaptureメソッドで、Image1のマウスキャプチャを無効にします。Image1がDropされた時のY座標を格納するメンバ変数myYDropPos変数に、現在のマウスポインタのY座標の値を指定します。
39   Private Sub Image1_MouseLeftButtonUp(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Image1.MouseLeftButtonUp
40     Image1.Cursor = Cursors.Arrow
41     Dim myImage As Image = DirectCast(sender, Image)
42     myMouseCaputer = False
43     myImage.ReleaseMouseCapture()
44     myYDropPos = myYPos
45   End Sub
46  
47 ■Image1をマウスでドラッグして移動した時の処理
48 senderオブジェクトの持っているImageの情報を、DirectCastでImage型に変換し、変数myImageで参照します。Image1上でマウスの左が押されている場合に、以下の処理を実行します。
49 移動したマウスポインタのY座標の値から、マウスの左ボタンが押された時点で取得されたY座標の値(myYPos)を減算した値を、変数myVerticalに格納します。
50 移動したマウスポインタのX座標の値から、マウスの左ボタンが押された時点で取得されたX座標の値(myXPos)を減算した値を、変数myHorizontalに格納します。
51 myVerticalの値に、GetValueメソッドで取得したImage1の、CanvasのTopの値を加算した値を、変数myNewTopに格納します。
52 myHorizontalの値に、GetValueメソッドで取得したImage1の、CanvasのLeftの値を加算した値を、変数myNewLeftに格納します。
53 SetValueメソッドで、Image1のTopとLeftの値に、myNewTopとmyNewLeftの値を指定します。
54 現在のマウスポインタのY座標の値を、myYPosメンバ変数に格納しておきます。同様に、現在のマウスポインタのX座標の値を、myXPosメンバ変数に格納しておきます。
55   Private Sub Image1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Image1.MouseMove
56     Dim myImage As Image = DirectCast(sender, Image)
57     If myMouseCaputer = True Then
58         Dim myVertical As Double = e.GetPosition(Nothing).Y - myYPos
59         Dim myHorizontal As Double = e.GetPosition(Nothing).X - myXPos
60         Dim myNewTop As Double = myVertical + DirectCast(myImage.GetValue(Canvas.TopProperty), Double)
61         Dim myNewLeft As Double = myHorizontal + DirectCast(myImage.GetValue(Canvas.LeftProperty), Double)
62         myImage.SetValue(Canvas.TopProperty, myNewTop)
63         myImage.SetValue(Canvas.LeftProperty, myNewLeft)
64         myYPos = e.GetPosition(Nothing).Y
65     myXPos = e.GetPosition(Nothing).X
66   End If
67 End Sub
68  
69 ■Image1上でマウスの左ボタンが離された時の処理
70 マウスが離された時のマウスポインタのY座標の値が300より大きかった場合、つまり、Targetキャンバス内にImageがドロップされた時の処理です。
71 VisualStateManager.GotoStateメソッドで、画像が縮小するImageSmallの VisualSateを実行します。VisualStateManager.GotoStateメソッドの書式は下記の通りです。
72 VisualStateManager.GotoState(状態を遷移させるコントロール,状態名,VisualTransitionを使うかどうかのBoolean値(使用する場合はTrue、それ以外はFalse)
73 Targetキャンバス内にある現在のマウスポインタの位置をmyCP変数に格納し、XとY座標の位置を取得します。XとY座標の値を取得したmyCP変数の値を、RippleEffectのCenterプロパティの値に指定します。RippleEffectのストーリーボードを開始します。
74 マウスが離された時のマウスポインタのY座標の値が300以外の場合は、画像が元の状態に戻る(拡大する)、ImageLargeのVisualStateを実行します。
75   Private Sub Image1Dropped(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
76     If myYDropPos > 300 Then
77         VisualStateManager.GoToState(Me, "ImageSmall", True)
78         Dim myCP As Point = e.GetPosition(Target)
79         myCP.X = myCP.X / Target.ActualWidth
80         myCP.Y = myCP.Y / Target.ActualHeight
81         myRippleEffect.Center = myCP
82         RippleStoryboard.Begin()
83     Else
84         VisualStateManager.GoToState(Me, "ImageLarge", True)
85     End If
86   End Sub
87  
88 ■Image1のMouseLeftButtonDownイベント時に実行される処理
89   マウスが押下された時のマウスポインタのY座標の値が、300より小さい場合は(マウスポインタがSourceという名前のCanvas内にあった時(図3参照))、処理を中止します。マウスポインタがSourceという名前のCanvas内にあった時には、画像をドラッグ&ドロップしても画像は何も変化しません。それ以外は、画像が拡大するImageLargeのVisualStateを実行します。
90   Private Sub Image1Larged(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
91     If myYDropPos < 300 Then
92         Exit Sub
93     Else
94         VisualStateManager.GoToState(Me, "ImageLarge", True)
95     End If
96   End Sub
97 End Class

你可能感兴趣的:(Silverlight)