电子书阅读器单页面布局Windows Phone 8.1 C#Xamarin

时间:2017-07-25 09:11:42

标签: c# xaml xamarin windows-phone-8.1

首先我想提一下,自从我开始研究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);
            }
        }
    }
}

0 个答案:

没有答案