首先我想提一下,自从我开始研究WP 8.1以来只有一周,所以请耐心等待。如果您需要澄清或信息,请随时发表评论。
我正在尝试使用Xamarin Native C#为Windows Phone 8.1创建电子书阅读器。
我已成功实施PageTurn7(除了一些动画错误)。但是,我的要求是有一个页面可以左右滑动(使用页面卷曲动画),而不是像我现在一样有2页。我尝试进行必要的更改,但没有运气。任何建议,想法或帮助都是最受欢迎的。
以下是我到目前为止的工作源代码:
ReadingPage.xaml
<Page
x:Class="epub_reader.WinPhone.ReadingPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:epub_reader.WinPhone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<LinearGradientBrush x:Key="LeftShadow" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#00000000" Offset="0.0" />
<GradientStop Color="#30000000" Offset="1.0" />
</LinearGradientBrush>
<LinearGradientBrush x:Name="RightShadow" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#30000000" Offset="0.0" />
<GradientStop Color="#00000000" Offset="1.0" />
</LinearGradientBrush>
</Page.Resources>
<Grid x:Name="grid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid x:Name="LayoutRoot" Background="#202020" Margin="0,50,0,40">
<Canvas x:Name="PageTurnCanvas" Width="1040" Height="720" HorizontalAlignment="Center" VerticalAlignment="Center">
<Canvas.RenderTransform>
<ScaleTransform x:Name="ZoomTransform" CenterX="520" CenterY="328" />
</Canvas.RenderTransform>
</Canvas>
</Grid>
</Grid>
</Page>
ReadingPage.xaml.cs
void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
{
ZoomTransform.ScaleX = ZoomTransform.ScaleY = (this.ActualWidth / PageTurnCanvas.Width) * 0.95;
}
private Canvas generateLeftCanvas(string filename)
{
SolidColorBrush whiteBrush = new SolidColorBrush();
whiteBrush.Color = Colors.White;
Canvas canvas = new Canvas();
canvas.Width = 520;
canvas.Height = 720;
canvas.Background = whiteBrush;
canvas.Margin = new Thickness(0, 0, 0, 0);
if (filename != "")
{
ImageSource imgSource = new BitmapImage(new Uri("ms-appx:///Assets/" + filename));
Image image = new Image();
image.Source = imgSource;
image.Width = 512;
image.Margin = new Thickness(8, 8, 0, 0);
canvas.Children.Add(image);
}
Rectangle rectangle = new Rectangle();
rectangle.Width = 32;
rectangle.Height = 720;
rectangle.Fill = this.Resources["LeftShadow"] as LinearGradientBrush;
rectangle.Margin = new Thickness(488, 0, 0, 0);
canvas.Children.Add(rectangle);
return canvas;
}
private Canvas generateRightCanvas(string filename)
{
SolidColorBrush whiteBrush = new SolidColorBrush();
whiteBrush.Color = Colors.White;
Canvas canvas = new Canvas();
canvas.Width = 520;
canvas.Height = 720;
canvas.Background = whiteBrush;
canvas.Margin = new Thickness(520, 0, 0, 0);
if (filename != "")
{
ImageSource imgSource = new BitmapImage(new Uri("ms-appx:///Assets/" + filename));
Image image = new Image();
image.Source = imgSource;
image.Width = 512;
image.Margin = new Thickness(0, 8, 0, 0);
canvas.Children.Add(image);
}
Rectangle rectangle = new Rectangle();
rectangle.Width = 32;
rectangle.Height = 720;
rectangle.Fill = this.Resources["RightShadow"] as LinearGradientBrush;
rectangle.Margin = new Thickness(0, 0, 0, 0);
canvas.Children.Add(rectangle);
return canvas;
}
private void renderBook()
{
pageTurn = new PageTurn();
Canvas temp1 = generateCanvas("1.jpg");
PageTurnCanvas.Children.Add(temp1);
Canvas temp2 = generateCanvas("8.jpg");
PageTurnCanvas.Children.Add(temp2);
Canvas temp3 = generateCanvas("4.jpg");
PageTurnCanvas.Children.Add(temp3);
Canvas temp4 = generateCanvas("2.jpg");
PageTurnCanvas.Children.Add(temp4);
Canvas temp5 = generateCanvas("6.jpg");
PageTurnCanvas.Children.Add(temp5);
Canvas temp6 = generateCanvas("3.jpg");
PageTurnCanvas.Children.Add(temp6);
Canvas temp7 = generateCanvas("7.jpg");
PageTurnCanvas.Children.Add(temp7);
Canvas temp8 = generateCanvas("5.jpg");
PageTurnCanvas.Children.Add(temp8);
pageTurn.AddSpread(temp1, temp2);
pageTurn.AddSpread(temp3, temp4);
pageTurn.AddSpread(temp5, temp6);
pageTurn.AddSpread(temp7, temp8);
pageTurn.Initialize(PageTurnCanvas);
pageTurn.Sensitivity = 1.2;
PageTurnCanvas.Visibility = Visibility.Visible;
}
PageTurn.cs
using System;
using System.Collections.Generic;
using Windows.UI.Xaml.Documents;
using System.Windows;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Markup;
using Windows.Foundation;
namespace epub_reader.WinPhone
{
public class PageTurn
{
public PageTurn()
{
}
private int _index = 0; // Current spread index
private double _width; // Width of each page
private double _height; // Height of each page
private int _count = 0; // Number of even/odd page pairs
private bool _turning = false; // True if page turn in progress
private bool _animating = false; // True if animated turn completion in progress
private double _percent = 0.0; // Percent turned (0 = 0%, 1 = 100%)
private double _startPos = -1; // X coordinate of initial mouse click
private int _direction = 0; // -1 = Turning left, 1 = Turning right
private double _step = 0.025; // Step size for animations
private double _shadowWidth = 16; // Maximum shadow width
private double _shadowBreak = 5; // Number of degrees required for shadow to attain maximum width
private double _sensitivity = 1.0; // Higher number -> More mouse movement required for full turn
private FrameworkElement _owner = null; // Owner of mouse capture
private List<Canvas> _evens = new List<Canvas>(); // Even pages
private List<Canvas> _odds = new List<Canvas>(); // Odd pages
private Polygon _shadow = null; // Polygon object used to draw shadow
private Storyboard _timer = null; // Storyboard timer for animations
private Canvas _canvas = null; // Canvas containing pages
private Canvas _workingOdd = null; // Working right page
private Canvas _workingEven = null; // Working left page
private PathGeometry _oddClipRegion = null;
private LineSegment _oddClipRegionLineSegment1 = null;
private LineSegment _oddClipRegionLineSegment2 = null;
private PathGeometry _evenClipRegion = null;
private LineSegment _evenClipRegionLineSegment1 = null;
private LineSegment _evenClipRegionLineSegment2 = null;
private LineSegment _evenClipRegionLineSegment3 = null;
private TransformGroup _transformGroup = null;
private RotateTransform _rotateTransform = null;
private TranslateTransform _translateTransform = null;
// XAML definition for clip region used on right-hand pages
private const string _opg =
"<PathGeometry xmlns=\"http://schemas.microsoft.com/client/2007\">" +
"<PathFigure StartPoint=\"0,0\">" +
"<LineSegment />" +
"<LineSegment />" +
"</PathFigure>" +
"</PathGeometry>";
// XAML definition for clip region used on left-hand pages
private const string _epg =
"<PathGeometry xmlns=\"http://schemas.microsoft.com/client/2007\">" +
"<PathFigure StartPoint=\"0,0\">" +
"<LineSegment Point=\"0,0\" />" +
"<LineSegment Point=\"0,0\" />" +
"<LineSegment Point=\"0,0\" />" +
"</PathFigure>" +
"</PathGeometry>";
// XAML definition for transforms used on left-hand pages
private const string _tg =
"<TransformGroup xmlns=\"http://schemas.microsoft.com/client/2007\">" +
"<RotateTransform />" +
"<TranslateTransform />" +
"</TransformGroup>";
// XAML definition for Storyboard timer
private const string _sb = "<Storyboard xmlns=\"http://schemas.microsoft.com/client/2007\" Duration=\"0:0:0.01\" />";
// XAML definition for shadow polygon
private const string _poly =
"<Polygon xmlns=\"http://schemas.microsoft.com/client/2007\" Canvas.ZIndex=\"4\" Fill=\"Black\" Opacity=\"0.2\" Points=\"0,0 0,0 0,0 0,0\" Visibility=\"Collapsed\">" +
"<Polygon.Clip>" +
"<RectangleGeometry Rect=\"0,0,{0},{1}\" />" +
"</Polygon.Clip>" +
"</Polygon>";
public event EventHandler PageTurned;
public int CurrentSpreadIndex
{
get { return _index; }
}
public int SpreadCount
{
get { return _count; }
}
public double Sensitivity
{
get { return _sensitivity; }
set { _sensitivity = value; }
}
public void Initialize(Canvas canvas)
{
_canvas = canvas;
// Create a Storyboard for timing animations
_timer = (Storyboard)XamlReader.Load(_sb);
//_timer.Completed += new EventHandler(OnTimerTick);
_timer.Completed += OnTimerTick;
// Create a PathGeometry for clipping right-hand pages
_oddClipRegion = (PathGeometry)XamlReader.Load(_opg);
_oddClipRegionLineSegment1 = (LineSegment)_oddClipRegion.Figures[0].Segments[0];
_oddClipRegionLineSegment2 = (LineSegment)_oddClipRegion.Figures[0].Segments[1];
// Create a PathGeometry for clipping left-hand pages
string xaml = String.Format(_epg, _evens[0].Height);
_evenClipRegion = (PathGeometry)XamlReader.Load(xaml);
_evenClipRegionLineSegment1 = (LineSegment)_evenClipRegion.Figures[0].Segments[0];
_evenClipRegionLineSegment2 = (LineSegment)_evenClipRegion.Figures[0].Segments[1];
_evenClipRegionLineSegment3 = (LineSegment)_evenClipRegion.Figures[0].Segments[2];
// Create a TransformGroup for transforming left-hand pages
_transformGroup = (TransformGroup)XamlReader.Load(_tg);
_rotateTransform = (RotateTransform)_transformGroup.Children[0];
_translateTransform = (TranslateTransform)_transformGroup.Children[1];
// Initialize internal variables
_count = _evens.Count;
_width = _evens[0].Width;
_height = _evens[0].Height;
// Create a Polygon to provide shadow during page turns
_shadow = (Polygon)XamlReader.Load(String.Format(_poly, _width * 2, _height));
_canvas.Children.Add(_shadow);
// Initialize z-order
InitializeZOrder();
}
private void OnTimerTick(object sender, object e)
{
_percent += _step;
if (_percent < 0.0)
_percent = 0.0;
else if (_percent > 1.0)
_percent = 1.0;
TurnTo(_percent);
if (_percent == 0.0)
{
if (_direction == 1)
{
_index--;
if (PageTurned != null)
PageTurned(this, EventArgs.Empty);
}
Reset();
}
else if (_percent == 1.0)
{
if (_direction == -1)
{
_index++;
if (PageTurned != null)
PageTurned(this, EventArgs.Empty);
}
Reset();
}
else
_timer.Begin();
}
public void AddSpread(Canvas left, Canvas right)
{
left.PointerPressed += Left_PointerPressed; ; ;
//left.MouseLeftButtonDown += new MouseButtonEventHandler(OnBeginRightTurn);
left.PointerMoved += Left_PointerMoved;
//left.MouseMove += new MouseEventHandler(OnContinueRightTurn);
left.PointerReleased += Left_PointerReleased; ;
//left.MouseLeftButtonUp += new MouseButtonEventHandler(OnEndRightTurn);
_evens.Add(left);
right.PointerPressed += Right_PointerPressed;
right.PointerMoved += Right_PointerMoved;
right.PointerReleased += Right_PointerReleased;
_odds.Add(right);
}
private void Right_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (_animating)
return; // Do nothing if animation in progress
// Do nothing if trying to turn left but last
// page is displayed
if (_index == _count - 1)
return;
// Start a left turn
_turning = true;
_direction = -1;
_percent = 0.0;
_startPos = e.GetCurrentPoint((FrameworkElement)sender).Position.X;
_owner = (FrameworkElement)sender;
((FrameworkElement)sender).CapturePointer(e.Pointer);
// Turn page to specified angle
TurnTo(_percent);
// Cache references to "working" pages
_workingOdd = _odds[_index];
_workingEven = _evens[_index + 1];
// Assign clipping regions and transforms to relevant canvases
RectangleGeometry rect = new RectangleGeometry();
rect.Transform = _oddClipRegion.Transform;
rect.Rect = _oddClipRegion.Bounds;
_workingOdd.Clip = rect;
//_workingOdd.Clip = _oddClipRegion;
//_workingEven.Clip = _evenClipRegion;
RectangleGeometry rect2 = new RectangleGeometry();
rect2.Rect = _evenClipRegion.Bounds;
rect2.Transform = _evenClipRegion.Transform;
_workingEven.Clip = rect2;
_workingEven.RenderTransform = _transformGroup;
// Set z-indexes for a left turn
_evens[_index + 1].SetValue(Canvas.ZIndexProperty, 2);
_odds[_index + 1].SetValue(Canvas.ZIndexProperty, 0);
}
private void Right_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (_animating)
return; // Do nothing if animation in progress
if (_turning)
{
// Compute change in X
double dx = _startPos - e.GetCurrentPoint((FrameworkElement)sender).Position.X;
// If mouse moved right, update _startPos so page
// begins turning with first move left
if (dx < 0)
{
_startPos = e.GetCurrentPoint((FrameworkElement)sender).Position.X;
return;
}
// Compute turn percentage based on change in X
double percent = dx / (_width * _sensitivity);
if (percent > 1.0)
percent = 1.0;
else if (percent < 0.0)
percent = 0.0;
// Exit now if no change
if (percent == _percent)
return;
// Update percent turned
_percent = percent;
// Turn page to specified angle
TurnTo(_percent);
}
}
private void Right_PointerReleased(object sender, PointerRoutedEventArgs e)
{
if (_animating)
return; // Do nothing if animation in progress
if (_turning)
CompleteTurn();
}
private void Left_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (_animating)
return; // Do nothing if animation in progress
// Do nothing if trying to turn right but first
// page is displayed
if (_index == 0)
return;
// Start a right turn
_turning = true;
_direction = 1;
_percent = 1.0;
_startPos = e.GetCurrentPoint((FrameworkElement)sender).Position.X;
_owner = (FrameworkElement)sender;
((FrameworkElement)sender).CapturePointer(e.Pointer);
// Turn page to specified angle
TurnTo(_percent);
// Cache references to "working" pages
_workingOdd = _odds[_index - 1];
_workingEven = _evens[_index];
// Assign clipping regions and transforms to relevant canvases
RectangleGeometry rect = new RectangleGeometry();
rect.Transform = _oddClipRegion.Transform;
rect.Rect = _oddClipRegion.Bounds;
_workingOdd.Clip = rect;
//_workingOdd.Clip = _oddClipRegion;
//_workingEven.Clip = _evenClipRegion;
RectangleGeometry rect2 = new RectangleGeometry();
rect2.Rect = _evenClipRegion.Bounds;
rect2.Transform = _evenClipRegion.Transform;
_workingEven.Clip = rect2;
_workingEven.RenderTransform = _transformGroup;
// Set z-indexes for a right turn
_evens[_index].SetValue(Canvas.ZIndexProperty, 3);
_evens[_index - 1].SetValue(Canvas.ZIndexProperty, 0);
_odds[_index - 1].SetValue(Canvas.ZIndexProperty, 2);
}
private void Left_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (_animating)
return; // Do nothing if animation in progress
if (_turning)
{
// Compute change in X
double dx = e.GetCurrentPoint((FrameworkElement)(((FrameworkElement)sender).Parent)).Position.X - _startPos;
// If mouse moved left, update _startPos so page
// begins turning with first move right
if (dx < 0)
{
_startPos = e.GetCurrentPoint((FrameworkElement)(((FrameworkElement)sender).Parent)).Position.X;
return;
}
// Compute turn percentage based on change in X
double percent = 1.0 - (dx / (_width * _sensitivity));
if (percent > 1.0)
percent = 1.0;
else if (percent < 0.0)
percent = 0.0;
// Exit now if no change
if (percent == _percent)
return;
// Update percent turned
_percent = percent;
// Turn page to specified angle
TurnTo(this._percent);
}
}
private void Left_PointerReleased(object sender, PointerRoutedEventArgs e)
{
if (_animating)
return; // Do nothing if animation in progress
if (_turning)
CompleteTurn();
}
public void GoToSpread(int index)
{
if (index != _index && index > 0 && index < _count)
{
_index = index;
InitializeZOrder();
if (PageTurned != null)
PageTurned(this, EventArgs.Empty);
}
}
private void TurnTo(double percent)
{
// Compute angle of rotation
double degrees = 45 - (percent * 45);
double radians = degrees * Math.PI / 180;
// Compute x coordinates along bottom of canvas
double dx1 = _width - (percent * _width);
double dx2 = _width - dx1;
// Compute tangent of rotation angle
double tan = Math.Tan(radians);
// Configure clipping region for right-hand page
double p2y;
if (tan == 0)
p2y = _height;
else
p2y = _height + (dx1 / tan);
double p3x = p2y * tan;
_oddClipRegionLineSegment1.Point = new Point(0, p2y);
_oddClipRegionLineSegment2.Point = new Point(p3x, 0);
// Configure clipping region for left-hand page
double p7x = dx2 - (_height * tan);
if (p7x >= 0.0) // 4-corner clipping region
{
_evenClipRegion.Figures[0].StartPoint = new Point(0, 0);
_evenClipRegionLineSegment1.Point = new Point(0, _height);
_evenClipRegionLineSegment2.Point = new Point(dx2, _height);
_evenClipRegionLineSegment3.Point = new Point(p7x, 0);
}
else // 3-corner clipping region
{
double y = _height - (dx2 / tan);
_evenClipRegion.Figures[0].StartPoint = _evenClipRegionLineSegment3.Point = new Point(0, y);
_evenClipRegionLineSegment1.Point = new Point(0, _height);
_evenClipRegionLineSegment2.Point = new Point(dx2, _height);
}
// Apply clipping regions and transforms
_rotateTransform.CenterX = dx2;
_rotateTransform.CenterY = _height;
_rotateTransform.Angle = 2 * degrees;
_translateTransform.X = 2 * (_width - dx2);
// Configure shadow
if (percent == 0.0 || percent == 1.0)
{
_shadow.Visibility = Visibility.Collapsed;
return;
}
_shadow.Visibility = Visibility.Visible;
double min = this._shadowBreak;
double max = 45 - this._shadowBreak;
double width;
if (degrees > min && degrees < max)
width = _shadowWidth;
else
{
if (degrees <= min)
width = (degrees / _shadowBreak) * _shadowWidth;
else // degrees >= max
width = ((45 - degrees) / _shadowBreak) * _shadowWidth;
}
double x1 = _width + dx1 + (_height * tan);
double x2 = _width + dx1;
double y2 = _height;
double x3 = x2 + width;
double y3 = _height;
double x4 = x1 + width;
_shadow.Points[0] = new Point(x1, 0);
_shadow.Points[1] = new Point(x2, y2);
_shadow.Points[2] = new Point(x3, y3);
_shadow.Points[3] = new Point(x4, 0);
}
private void CompleteTurn()
{
if (_percent == 0.0)
{
if (_direction == 1)
{
_index--;
if (PageTurned != null)
PageTurned(this, EventArgs.Empty);
}
Reset();
return;
}
if (_percent == 1.0)
{
if (_direction == -1)
{
_index++;
if (PageTurned != null)
PageTurned(this, EventArgs.Empty);
}
Reset();
return;
}
if (_percent < 0.5)
_step = -Math.Abs(_step);
else
_step = Math.Abs(_step);
_animating = true;
_timer.Begin();
}
private void Reset()
{
_turning = false;
_animating = false;
_direction = 0;
if (_owner != null)
_owner.ReleasePointerCaptures();
_owner = null;
if (_workingOdd != null && _workingOdd.Clip != null)
_workingOdd.Clip = null;
if (_workingEven != null && _workingEven.Clip != null)
_workingEven.Clip = null;
if (_workingEven != null && _workingEven.RenderTransform != null)
_workingEven.RenderTransform = null;
_workingOdd = null;
_workingEven = null;
_shadow.Visibility = Visibility.Collapsed;
InitializeZOrder();
}
private void InitializeZOrder()
{
for (int i = 0; i < _count; i++)
{
_evens[i].SetValue(Canvas.ZIndexProperty, (i == _index) ? 1 : -1);
_odds[i].SetValue(Canvas.ZIndexProperty, (i == _index) ? 1 : -1);
}
}
}
}