第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
プロパティ名再生ヘッドの位置(秒)
00.11.3
Frequency40300
Magnitude00.020
Phase000

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

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

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

リスト3 (MainPage.xaml.vb)
01Option Strict On
02Partial 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
15Imageが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のマウスキャプチャを有効にします。
28Private 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をマウスでドラッグして移動した時の処理
48senderオブジェクトの持っているImageの情報を、DirectCastでImage型に変換し、変数myImageで参照します。Image1上でマウスの左が押されている場合に、以下の処理を実行します。
49移動したマウスポインタのY座標の値から、マウスの左ボタンが押された時点で取得されたY座標の値(myYPos)を減算した値を、変数myVerticalに格納します。
50移動したマウスポインタのX座標の値から、マウスの左ボタンが押された時点で取得されたX座標の値(myXPos)を減算した値を、変数myHorizontalに格納します。
51myVerticalの値に、GetValueメソッドで取得したImage1の、CanvasのTopの値を加算した値を、変数myNewTopに格納します。
52myHorizontalの値に、GetValueメソッドで取得したImage1の、CanvasのLeftの値を加算した値を、変数myNewLeftに格納します。
53SetValueメソッドで、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
67End Sub
68 
69■Image1上でマウスの左ボタンが離された時の処理
70マウスが離された時のマウスポインタのY座標の値が300より大きかった場合、つまり、Targetキャンバス内にImageがドロップされた時の処理です。
71VisualStateManager.GotoStateメソッドで、画像が縮小するImageSmallの VisualSateを実行します。VisualStateManager.GotoStateメソッドの書式は下記の通りです。
72VisualStateManager.GotoState(状態を遷移させるコントロール,状態名,VisualTransitionを使うかどうかのBoolean値(使用する場合はTrue、それ以外はFalse)
73Targetキャンバス内にある現在のマウスポインタの位置を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
97End Class

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值