现在的位置: 首页 > 综合 > 正文

Windows Phone 7 – Image加上Zoom in/out功能 缩放功能

2012年10月03日 ⁄ 综合 ⁄ 共 4758字 ⁄ 字号 评论关闭

Windows Phone 7 - Image加上Zoom in/out功能

 

最近不小心迷上用手機看漫畫這件事,所以想說寫一個自己的漫畫程式,這樣可以選擇自己覺得

取得圖像資料比較快且穩定的網站。不過在撰寫過程裡,對於Image的處理卻是最為困難的地方。

不過還好,在網路上找到了這一篇資料<Windows Phone 7: correct pinch zoom in Silverlight>,裡面

針對圖像的處理提供了最完整的解釋,往下針對該篇文章提到的部分,加以說明。

〉定義XAML中Image的呈現樣式

   1: <Grid x:Name="LayoutRoot" Background="Transparent">
   2:     <Image x:Name="ImgZoom"
   3:            Source="sample.jpg"
   4:            Stretch="UniformToFill"
   5:            RenderTransformOrigin="0,0"> 
   6:         <toolkit:GestureService.GestureListener>
   7:             <!-- 定義Pinch系列的事件,DoubleTap回到原圖,Drag圖像移動-->
   8:             <toolkit:GestureListener
   9:                     PinchStarted="OnPinchStarted"
  10:                     PinchDelta="OnPinchDelta"
  11:                     DragDelta="OnDragDelta"
  12:                     DoubleTap="OnDoubleTap"/>
  13:         </toolkit:GestureService.GestureListener>
  14:         <Image.RenderTransform>
  15:             <!-- 定義CompositeTransform支援Scale與Translate的特效 -->
  16:             <CompositeTransform
  17:                     ScaleX="1" ScaleY="1"
  18:                     TranslateX="0" TranslateY="0"/>
  19:         </Image.RenderTransform>
  20:     </Image>
  21: </Grid>

如果針對GestureService不是非常熟悉的地方,可以參考<Windows Phone 7 - 淺談手勢(Gestures)運作>的說明。

上述程式主要針對Pinch、Drag與DoubleTap三種手勢進行事件的定義,並且實作了二種RenderTransform支援

Image圖像內容的Scale、Translate二種特效。

Image

在Image控件裡幾個屬性,在使用RenderTransform時需要注意的,如下:

屬性 說明
ScaleX 屬於ScaleTransform的重要屬性。
控制物件的Scale X比例(横向擴大),一種二維的X-Y坐標系統。
SacleY 屬於ScaleTransform的重要屬性。
控制物件的Scale Y比例(直向擴大),一種二維的X-Y坐標系統。
TranslateX 屬於TranslateTransform的重要屬性。
控制物件的TranslatesX比例(横向移動),一種二維的X-Y坐標系統。
TranslateY 屬於TranslateTransform的重要屬性。
控制物件的TranslatesX比例(直向移動),一種二維的X-Y坐標系統。

在處理RenderTransform裡還有包括:RotateTransformSkewTransformTranslateTransformMatrixTransform等,

這些Transform可透過TransformGroup組合起來一同管理,讓套用的物件可同時具有這些效果。

定義好了圖像的基本效果與XAML後,接下來便來看看,實際如何處理:Pinch、Drag與DoubleTap的手勢事件;

〉處理Pinch事件(PinchStarted與PinchDelta)

Pinch代表運用二個手指按在螢幕上,進行二指間的拉近與拉遠移動所觸發的事件。

在<Windows Phone 7 - 淺談手勢(Gestures)運作>提到二個事件的定義,如下:

PinchStarted:代表Pinched事件的開始,即是二個手指剛觸控於螢幕時;

PinchDelta:代表Pinched事件執行的過程,即時二個手指間距移動時觸發的事件;

(1) 在PinchStarted記下目前圖像控件的二個手指點擊的位置與設定Scale比例為1

   1: /// <summary>
   2: /// Initializes the zooming operation
   3: /// </summary>
   4: private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
   5: {
   6:     //取得目前二個手指在圖像控件的座置,並且設定目前Scale比率為1
   7:     _oldFinger1 = e.GetPosition(ImgZoom, 0);
   8:     _oldFinger2 = e.GetPosition(ImgZoom, 1);
   9:     
  10:     //設定為1,代表以目前圖像的狀態進行Scale的調整
  11:     _oldScaleFactor = 1;    
  12: }

(2) 在PinchDelta進行一系列移動時的圖像Scale與座標移動的計算

   1: /// <summary>
   2: /// Computes the scaling and translation to correctly zoom around your fingers.
   3: /// </summary>
   4: private void OnPinchDelta(object sender, PinchGestureEventArgs e)
   5: {
   6:     //取得移動的距離比率 / 目前的Scale比率,取得對應的Scale比率
   7:     var scaleFactor = e.DistanceRatio / _oldScaleFactor;
   8:     //檢查新的Scale比率是否合法
   9:     if (!IsScaleValid(scaleFactor))
  10:         return;
  11:  
  12:     //取得新的二個手指座標
  13:     var currentFinger1 = e.GetPosition(ImgZoom, 0);
  14:     var currentFinger2 = e.GetPosition(ImgZoom, 1);
  15:  
  16:     //根據目前的二手指座標、上一個二手指座標、圖像的座標、新Scale比率,重新建立一個Point
  17:     var translationDelta = GetTranslationDelta(
  18:         currentFinger1,
  19:         currentFinger2,
  20:         _oldFinger1,
  21:         _oldFinger2,
  22:         ImagePosition,
  23:         scaleFactor);
  24:  
  25:     //更新儲存現在的手指座標與Scale比率
  26:     _oldFinger1 = currentFinger1;
  27:     _oldFinger2 = currentFinger2;
  28:     _oldScaleFactor = e.DistanceRatio;
  29:  
  30:     //更新圖像Scale比率與圖像座標
  31:     UpdateImageScale(scaleFactor);
  32:     UpdateImagePosition(translationDelta);
  33: }

透過在該PinchDelta擷取到的(1) 移動距離搭配目前的Scale比率,計算出的Scale比率;並且因為比率的改變,也要讓

(2) 圖像放大的位置是二指間的圖像區域,因此再透過二指間的座標與Scale比率等參數,計算新的座標來配合Scale

的變動;

在上述的程式裡有二個事件參數,它們均繼承GestureEventArgs加上了Pinch的部分:

PinchStartedGestureEventArgs:定義了二個觸控點在啟動時需要擷取到的基本資料;

屬性/方法 說明
GetPosition 回傳在相對應UIElement中二個觸控點(0或1)任一個的座標位置。
Distance 二個觸控點之間的距離。

PinchGestureEventArgs:定義在Pinch過程中相對於距離、角度的處理值;

屬性/方法 說明
DistanceRatio 回傳接觸點之間的當前距離/原來的接觸點之間的距離的比值。
TotalAngleDelta 回傳當前的觸摸位置和原始觸摸位置之間的角度差。

〉處理Drag事件

Drag負責一個手指按在螢幕上,移動時連著帶動有監聽Drag事件的物件跟著移動。此程式增加Drag的機制讓圖像

可以跟著Drag的新座標進行移動的效果。如下程式:

   1: /// <summary>
   2: /// Moves the image around following your finger.
   3: /// </summary>
   4: private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
   5: {
   6:     //取得移動的新座標
   7:     var translationDelta = new Point(e.HorizontalChange, e.VerticalChange);
   8:  
   9:     //驗證是否超過Scale後可移動範圍、目前圖像移動與實體大小的差距
  10:     if (IsDragValid(1, translationDelta))
  11:         UpdateImagePosition(translationDelta);
  12: }

〉處理DoubleTab事件

DoubleTab事件發生連續快速二次Tap(輕敲)動作於UIElement。此程式增加了在圖像上進行DoubleTab之後,將圖像復原

成原來的樣子。如下程式:

   1: /// <summary>
   2: /// Resets the image scaling and position
   3: /// </summary>
   4: private void OnDoubleTap(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
   5: {
   6:     TotalImageScale = 1;
   7:     ImagePosition = new Point(0, 0);
   8:     //呼叫ApplyScale()與ApplyPosition()根據TotalImageScale與ImagePosition
   9:     //復原圖像的原始比例
  10:     ApplyScale();
  11:     ApplyPosition();
  12: }

〉相關的副程式

(1) 取得隨著Scale與座標改變圖像的新座標:GetTranslationDelta()

   1: /// <summary>
   2: /// Computes the translation needed to keep the image centered between your fingers.
   3: /// </summary>
   4: private Point GetTranslationDelta(
   5:     Point currentFinger1, Point currentFinger2,
   6:     Point oldFinger1, Point oldFinger2,
   7:     Point currentPosition, double scaleFactor)
   8: {
   9:     var newPos1 = new Point(
  10:      currentFinger1.X + (currentPosition.X - oldFinger1.X) * scaleFactor,
  11:      currentFinger1.Y + (currentPosition.Y - oldFinger1.Y) * scaleFactor);
  12:  
  13:     var newPos2 = new Point(

抱歉!评论已关闭.