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

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

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

3

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

3

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

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

新規プロジェクトの作成

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

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

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

コントロールの配置

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

3

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

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

01 <UserControl x:Class="SL4_ImageDropRipple.MainPage"
06   mc:Ignorable="d"
07   d:DesignHeight="300" d:DesignWidth="400" Width="800" Height="600">
08   <Grid x:Name="LayoutRoot" Background="White">
09     <Canvas Height="300" HorizontalAlignment="Left" Margin="0,300,0,0" x:Name="Target" VerticalAlignment="Top" Width="800" />
10     <Canvas Height="300" HorizontalAlignment="Left" x:Name="Source" VerticalAlignment="Top" Width="800" />
11   </Grid>
12 </UserControl>

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

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

3

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

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

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

01 (1)x:NameがTargetの<Canvas> 要素內に3個の<Image>要素を配置しています。Widthは160、Heightは120としています。
02 (2)x:NameがSourceの<Canvas>要素內に1個の<Image>要素を配置しています。Widthは320、Heightは240としています。
03 <UserControl x:Class="SL4_ImageDropRipple.MainPage"
08     mc:Ignorable="d"
09     d:DesignHeight="300" d:DesignWidth="400" Width="800" Height="600">
10  
11     <Grid x:Name="LayoutRoot" Background="White">
12     <Canvas Height="300" HorizontalAlignment="Left" Margin="0,300,0,0" x:Name="Target" VerticalAlignment="Top" Width="800"> ■(1)
13         <Image Canvas.Left="614" Canvas.Top="17" Height="120" Name="Image2" Stretch="Fill" Width="160" Source="/SL4_ImageDropRipple;component/Image/桜.jpg" />
14         <Image Canvas.Left="335" Canvas.Top="163" Height="120" Name="Image3" Stretch="Fill" Width="160" Source="/SL4_ImageDropRipple;component/Image/黃色い花.jpg" />
15         <Image Canvas.Left="31" Canvas.Top="17" Height="120" Name="Image4" Stretch="Fill" Width="160" Source="/SL4_ImageDropRipple;component/Image/ポピー.jpg" />
16     </Canvas>
17     <Canvas Height="300" HorizontalAlignment="Left" x:Name="Source" VerticalAlignment="Top" Width="800"> ■(2)
18         <Image Canvas.Left="230" Canvas.Top="27" Height="240" Name="Image1" Stretch="Fill" Width="320" Source="/SL4_ImageDropRipple;component/Image/菜の花.jpg" />
19     </Canvas>
20   </Grid>
21 </UserControl>

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

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

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

3

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

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

3

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

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

3

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

Canvasの背景色の設定

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

3

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

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

3

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

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

3

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

狀態(S)の設定

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

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

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

3

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

3

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

3

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

3

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

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

3

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

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

3

図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が選択された狀態で行ってください。

3

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

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

Ripple特殊効果の設定

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

3

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

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

3

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

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

3

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

Storyboardの作成

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

3

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

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

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

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

3

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

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

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

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

3

図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)

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章