WP8图片缩放功能实现

2023-05-25,,

最近在学习WP8,想实现WP微信中查看图片时的放大缩小功能

网上找了两个解决方案:

1 利用GestureListener

这个类在Microsoft.Phone.Controls.Toolkit中,GestureListener可以捕捉到WP手机屏幕上的手势动作。

XAML文件:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Image x:Name="_image" Source="/Assets/test.jpg" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<ScaleTransform x:Name="transform"/>
</Image.RenderTransform>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener
DoubleTap="OnDoubleTap"DragDelta="OnDragDelta"
Flick="OnFlick"
PinchStarted="OnPinchStarted" PinchDelta="OnPinchDelta" PinchCompleted="OnPinchCompleted"/>
</toolkit:GestureService.GestureListener> </Image>
</Grid>

cs文件:

       double initialScale;

        public Zoom()
{
InitializeComponent();
} private void OnDoubleTap(object sender, Microsoft.Phone.Controls.GestureEventArgs e)
{
transform.ScaleX = transform.ScaleY = ;
} private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
{
transform.CenterX -= e.HorizontalChange;
transform.CenterY -= e.VerticalChange;
} private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
{
initialScale = transform.ScaleX;
} private void OnPinchDelta(object sender, PinchGestureEventArgs e)
{
transform.ScaleX = transform.ScaleY = initialScale * e.DistanceRatio;
} private void OnPinchCompleted(object sender, PinchGestureEventArgs e)
{ } private void OnFlick(object sender, FlickGestureEventArgs e)
{ }

前面是在XAML代码中构建GestureListener,在后台代码中也可以构建GestureListener。

               Grid grd = new Grid
{
Height = ,
Width = ,
Background = new SolidColorBrush(Colors.Black),
Opacity = 0.9,
}; Image img = new Image { Source = source };
grd.Children.Add(img);
//设置图片变换类型为缩放
ScaleTransform transform = new ScaleTransform();
img.RenderTransform = transform; var gesListener= GestureService.GetGestureListener(img); gesListener.DoubleTap += (obj, arg) =>
{
transform.ScaleX = transform.ScaleY = ;
};
gesListener.DragDelta += (obj, arg) =>
{
transform.CenterX -= arg.HorizontalChange;
transform.CenterY -= arg.VerticalChange;
};
gesListener.PinchStarted += (obj, arg) =>
{
initialScale = transform.ScaleX;
};
gesListener.PinchDelta += (obj, arg) =>
{
transform.ScaleX = transform.ScaleY = initialScale * arg.DistanceRatio;
};

2 ViewportControl

XAML文件:

       <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ViewportControl x:Name="viewport"
ManipulationStarted="OnManipulationStarted" ManipulationDelta="OnManipulationDelta"
ManipulationCompleted="OnManipulationCompleted" ViewportChanged="viewport_ViewportChanged">
<Canvas x:Name="canvas">
<Image x:Name="TestImage" Source="/Assets/test.jpg"
RenderTransformOrigin="0,0" CacheMode="BitmapCache"
ImageOpened="OnImageOpened">
<Image.RenderTransform>
<ScaleTransform x:Name="xform"/>
</Image.RenderTransform>
</Image>
</Canvas>
</ViewportControl>
</Grid>

cs文件:

 const double MaxScale = ;

        double _scale = 1.0;
double _minScale;
double _coercedScale;
double _originalScale; Size _viewportSize;
bool _pinching;
Point _screenMidpoint;
Point _relativeMidpoint; BitmapImage _bitmap; public PinchAndZoom()
{
InitializeComponent(); BuildLocalizedApplicationBar();
} /// <summary>
/// Either the user has manipulated the image or the size of the viewport has changed. We only
/// care about the size.
/// </summary>
void viewport_ViewportChanged(object sender, System.Windows.Controls.Primitives.ViewportChangedEventArgs e)
{
Size newSize = new Size(viewport.Viewport.Width, viewport.Viewport.Height);
if (newSize != _viewportSize)
{
_viewportSize = newSize;
CoerceScale(true);
ResizeImage(false);
}
} /// <summary>
/// Handler for the ManipulationStarted event. Set initial state in case
/// it becomes a pinch later.
/// </summary>
void OnManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
_pinching = false;
_originalScale = _scale;
} /// <summary>
/// Handler for the ManipulationDelta event. It may or may not be a pinch. If it is not a
/// pinch, the ViewportControl will take care of it.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void OnManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
if (e.PinchManipulation != null)
{
e.Handled = true; if (!_pinching)
{
_pinching = true;
Point center = e.PinchManipulation.Original.Center;
_relativeMidpoint = new Point(center.X / TestImage.ActualWidth, center.Y / TestImage.ActualHeight); var xform = TestImage.TransformToVisual(viewport);
_screenMidpoint = xform.Transform(center);
} _scale = _originalScale * e.PinchManipulation.CumulativeScale; CoerceScale(false);
ResizeImage(false);
}
else if (_pinching)
{
_pinching = false;
_originalScale = _scale = _coercedScale;
}
} /// <summary>
/// The manipulation has completed (no touch points anymore) so reset state.
/// </summary>
void OnManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
_pinching = false;
_scale = _coercedScale;
} /// <summary>
/// When a new image is opened, set its initial scale.
/// </summary>
void OnImageOpened(object sender, RoutedEventArgs e)
{
_bitmap = (BitmapImage)TestImage.Source; // Set scale to the minimum, and then save it.
_scale = ;
CoerceScale(true);
_scale = _coercedScale; ResizeImage(true);
} /// <summary>
/// Adjust the size of the image according to the coerced scale factor. Optionally
/// center the image, otherwise, try to keep the original midpoint of the pinch
/// in the same spot on the screen regardless of the scale.
/// </summary>
/// <param name="center"></param>
void ResizeImage(bool center)
{
if (_coercedScale != && _bitmap != null)
{
double newWidth = canvas.Width = Math.Round(_bitmap.PixelWidth * _coercedScale);
double newHeight = canvas.Height = Math.Round(_bitmap.PixelHeight * _coercedScale); xform.ScaleX = xform.ScaleY = _coercedScale; viewport.Bounds = new Rect(, , newWidth, newHeight); if (center)
{
viewport.SetViewportOrigin(
new Point(
Math.Round((newWidth - viewport.ActualWidth) / ),
Math.Round((newHeight - viewport.ActualHeight) / )
));
}
else
{
Point newImgMid = new Point(newWidth * _relativeMidpoint.X, newHeight * _relativeMidpoint.Y);
Point origin = new Point(newImgMid.X - _screenMidpoint.X, newImgMid.Y - _screenMidpoint.Y);
viewport.SetViewportOrigin(origin);
}
}
} /// <summary>
/// Coerce the scale into being within the proper range. Optionally compute the constraints
/// on the scale so that it will always fill the entire screen and will never get too big
/// to be contained in a hardware surface.
/// </summary>
/// <param name="recompute">Will recompute the min max scale if true.</param>
void CoerceScale(bool recompute)
{
if (recompute && _bitmap != null && viewport != null)
{
// Calculate the minimum scale to fit the viewport
double minX = viewport.ActualWidth / _bitmap.PixelWidth;
double minY = viewport.ActualHeight / _bitmap.PixelHeight; _minScale = Math.Min(minX, minY);
} _coercedScale = Math.Min(MaxScale, Math.Max(_scale, _minScale)); } // Sample code for building a localized ApplicationBar
private void BuildLocalizedApplicationBar()
{
// Set the page's ApplicationBar to a new instance of ApplicationBar.
ApplicationBar = new ApplicationBar(); // Create a new button and set the text value to the localized string from AppResources.
ApplicationBarIconButton appBarButton = new ApplicationBarIconButton(new Uri("/Assets/appbar_info.png", UriKind.Relative));
appBarButton.Click += appBarButton_Click;
appBarButton.Text = AppResources.AppBarButtonInfoText;
ApplicationBar.Buttons.Add(appBarButton); } void appBarButton_Click(object sender, EventArgs e)
{
MessageBox.Show(AppResources.PinchZoomHelpText, AppResources.InfoCaption,MessageBoxButton.OK);
}

PS:测试的话应该部署到WP8手机中测试。

参考:

http://www.cnblogs.com/chengxingliang/archive/2011/08/15/2137377.html

http://www.cnblogs.com/JerryH/archive/2012/01/05/2312635.html

http://code.msdn.microsoft.com/wpapps/Image-Recipes-0c0b8fee

WP8图片缩放功能实现的相关教程结束。

《WP8图片缩放功能实现.doc》

下载本文的Word格式文档,以方便收藏与打印。