WinRT中的路径几何剪辑等效

时间:2014-04-07 07:02:38

标签: windows-8 windows-runtime winrt-xaml

今天我开始将为Windows Phone 7创建的页面转换示例here移植到WinRT(XAML,C#),以帮助在Stack Overflow中发布问题this。但在移植过程中,我遇到了页面的剪辑部分。在Windows手机示例中,他们使用路径几何裁剪来剪切页面。但在WinRT中似乎只有矩形几何支持剪切选项。

如何在WinRT中实现路径几何裁剪等类似功能?

您可以从here

下载示例Windows电话代码

请找到我尝试的源代码please download

请找到类PageTurn.cs,我在代码中注释了代码:

void left_PointerEntered(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
    //_workingOdd.Clip = _oddClipRegion;       
    //_workingEven.Clip = _evenClipRegion;
}

5 个答案:

答案 0 :(得分:12)

希望这对你有所帮助。

以下是XAML,可以准确了解您链接到的演示的外观:

路径计算 enter image description here

<强> IMAGE1

 <Grid Background="Black">
    <Grid Height="145" Width="210" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Border Margin="-3" BorderThickness="3" BorderBrush="White" Grid.ColumnSpan="2"></Border>
        <Image Grid.Column="0" Source="Images/1.jpg"></Image>
        <Image Grid.Column="1" Source="Images/2.jpg" ></Image>
        <Image Grid.Column="1" HorizontalAlignment="Left"  Source="Images/8.jpg" >
            <Image.Clip>
                <RectangleGeometry Rect="0,0,49,150"></RectangleGeometry>
            </Image.Clip>
        </Image>
        <Path Grid.ColumnSpan="2"  Data="M 180,0 L 153,145 L 85 120 L 160,-12"   >
            <Path.Fill>
                <ImageBrush ImageSource="Images/4.jpg"/>
            </Path.Fill>
        </Path>
        <!--polyline used for path image border-->
        <Polyline Points="180,0,160,-11,85,120,153,145" Margin="0,-2,0,0"  Stroke="White" StrokeThickness="3"  Grid.ColumnSpan="2"/>
    </Grid>
</Grid>

<强>图像2

    <Grid Background="Black">
    <Grid Width="290" Height="180" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Border Grid.Column="0"  BorderThickness="2,0,0,0" BorderBrush="White">
            <Image Stretch="Fill"  Source="Images/4.jpg"></Image>
        </Border>
        <Image Grid.Column="1" Source="Images/3.jpg" ></Image>
        <Path Grid.ColumnSpan="2"  Data="M 200,0 L 170,180 L 82.5 160 L 130 0 "   >
            <Path.Fill>
                <ImageBrush ImageSource="Images/6.jpg"/>
            </Path.Fill>
        </Path>
        <!--polyline used for path image border-->
        <Polyline Points="130,0,82.5,160,170,180"   Stroke="White" StrokeThickness="2"  Grid.ColumnSpan="2"/>
    </Grid>
</Grid>

<强>输出

enter image description here

您可以通过将image1和image2网格放在视图框中来扩大图像的大小,如下所示

 <Viewbox Width="500" Height="350">
    <Grid Width="290" Height="180"/>        
 </Viewbox>

答案 1 :(得分:7)

所以,让我们清楚事物的状态。

  1. WP 8.1
  2. 现在支持WinRT XAML
  3. WP Silverlight XAML可以胜过WinRT XAML
  4. 例如,WP SL XAML可以使用自定义路径进行剪辑
  5. WinRT XAML只能使用矩形进行剪裁
  6. 原因:矩形超出任何自定义形状,句号
  7. XAML团队提供性能特朗普功能
  8. 今天,XAML团队没有计划改变裁剪
  9. 现在我们了解这个问题。 我们还有其他选择吗?

    如果你想要剪辑图像,那么你很幸运。您可以创建任何形状的路径元素,并使用图像画笔绘制背景。这在技术上并不是剪裁,但你有相同的效果。

    <Path Data="M540,394 C544.208,422.053 538.553,441.447 514,466 C490.615,489.385 
    485.625,493.625 448,456 C423.947,431.947 425.435,394.188 486,374 C457.465,374 
    452,353.019 452,312 C452,280.568 446.005,289.33 478,268 C514.938,243.374 
    496.654,264 536,264 C538.338,275.69 546,280.948 546,294 C540.421,280.052 
    545.708,255.719 564,242 C577.778,231.667 594.285,223.858 610,216 C617.244,212.378 
    619.853,219.804 626,228 C630.353,233.805 671.625,322.65 620,302 C660.196,302 
    680,306.666 680,374 C680,393.824 652.592,424.592 614,386 C614,403.28 
    621.284,411.789 614,430 C607.693,445.768 601.833,454 580,454 C550.466,454 
    548.934,443.082 534,414" HorizontalAlignment="Left" Height="269.872" 
    Margin="433.483,215.058,0,0" Stretch="Fill" Stroke="Black" UseLayoutRounding="False" 
    VerticalAlignment="Top" Width="247.517">
        <Path.Fill>
            <ImageBrush Stretch="None" ImageSource="Assets/SplashScreen.png"/>
        </Path.Fill>
    </Path>
    

    这会产生这个:

    enter image description here

    但是还等一下。 ImageBrush本身可以转换。这意味着您可以在路径中移动图像的图像上执行翻译。此外,您还可以在图像上应用旋转。

    首先,考虑像FlipBoard那样的动画。这为您提供了一个简单的页面翻转动画,看起来非常棒,而不需要复杂的剪辑。看看这个演示:http://blog.jerrynixon.com/2012/12/walkthough-use-xamls-3d-planeprojection.html

    然后,你可能只是想复制那个Demo。没关系。下面的XAML将为您提供您想要的效果。它很容易制作动画:

    <Grid>
        <Rectangle Stroke="Black" Width="800" Height="400">
            <Rectangle.Fill>
                <ImageBrush Stretch="UniformToFill" ImageSource="Assets/car.jpg"/>
            </Rectangle.Fill>
        </Rectangle>
        <Grid Width="800" Height="400">
            <Grid.Clip>
                <RectangleGeometry Rect="0,-400,800,800" />
            </Grid.Clip>
            <Grid Width="800" Height="400" RenderTransformOrigin="0.5,0.5">
                <Grid.RenderTransform>
                    <CompositeTransform ScaleX="-1" Rotation="30.957" TranslateX="527" TranslateY="108"/>
                </Grid.RenderTransform>
                <Grid.Background>
                    <ImageBrush Stretch="UniformToFill" ImageSource="Assets/car.jpg"/>
                </Grid.Background>
                <Rectangle Fill="Purple" Opacity=".5" />
            </Grid>
        </Grid>
    </Grid>
    

    看起来像这样:

    这里是XAML,可以准确了解您链接到的演示的外观:

    <Grid Width="800" Height="200" Margin="283,283,283,285">
        <Grid.Clip>
            <RectangleGeometry Rect="-200,-200,1000,400" />
        </Grid.Clip>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="400" />
            <ColumnDefinition Width="400" />
        </Grid.ColumnDefinitions>
        <Path x:Name="Page2" Grid.Column="1" Data="M0.5,0.5 L495,-1 L399.5,199.5 L0.5,199.5 z" Stretch="Fill" Margin="0,-1.5,-95.5,0" UseLayoutRounding="False" RenderTransformOrigin="0.5,0.5" >
            <Path.RenderTransform>
                <CompositeTransform TranslateX="-200"/>
            </Path.RenderTransform>
            <Path.Fill>
                <ImageBrush Stretch="UniformToFill" ImageSource="Assets/Car2.jpg"/>
            </Path.Fill>
        </Path>
        <Path x:Name="Page4" Data="M94,2 L495,-1 L495,201 L0.5,199.5 z" Stretch="Fill" Margin="400,-3.5,-495.5,0.5" UseLayoutRounding="False" RenderTransformOrigin="0.5,0.5" >
            <Path.Fill>
                <ImageBrush Stretch="UniformToFill" ImageSource="Assets/Car4.jpg"/>
            </Path.Fill>
            <Path.RenderTransform>
                <CompositeTransform TranslateX="200"/>
            </Path.RenderTransform>
        </Path>
        <Image x:Name="Page1" Source="Assets/Car1.jpg" Grid.Column="0" Stretch="UniformToFill" />
        <Grid x:Name="Page3" Grid.Column="1" RenderTransformOrigin="0.5,0.5">
            <Grid.RenderTransform>
                <CompositeTransform TranslateX="-156" Rotation="25" TranslateY="-94" ScaleX="1.1" ScaleY="1.1"/>
            </Grid.RenderTransform>
            <Grid.Clip>
                <RectangleGeometry Rect="0,0,400,200" />
            </Grid.Clip>
            <Border BorderThickness="5,5,5,0" BorderBrush="White">
                <Border.RenderTransform>
                    <CompositeTransform TranslateX="175"/>
                </Border.RenderTransform>
                <Image x:Name="Page3Image" Source="Assets/Car3.jpg" Stretch="UniformToFill"/>
            </Border>
        </Grid>
    </Grid>
    

    看起来像这样:

    enter image description here

    我不确定这需要做多少调整才能做到正确,斯蒂芬。我的猜测是......很多。好消息是:你可以在GPU上进行动画转换,这样大部分都应该加速。 :)

    // Jerry

答案 2 :(得分:5)

我提供更完整的答案有点晚了,但我受到启发并开始致力于可重复使用的控件/页面转换。目前的原型与RenderTransformsClip Transforms非常合作,可以获得良好的独立动画支持。

enter image description here

我将使用WinRT XAML Toolkit的可重用控件,但同时您可以查看此代码:

<强> XAML

<Page
    x:Class="FlipControls.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:FlipControls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid
        x:Name="ManipulationGrid"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
        ManipulationMode="TranslateX,TranslateY,TranslateInertia"
        ManipulationStarted="ManipulationGrid_OnManipulationStarted"
        ManipulationDelta="ManipulationGrid_OnManipulationDelta"
        ManipulationCompleted="ManipulationGrid_OnManipulationCompleted">
        <Grid
            x:Name="Page1">
            <Grid.Clip>
                <RectangleGeometry
                    Rect="0,0,80000,80000">
                    <RectangleGeometry.Transform>
                        <TransformGroup>
                            <TranslateTransform
                                x:Name="Page1ClipTranslateTransform" />
                            <RotateTransform
                                x:Name="Page1ClipRotateTransform" />
                        </TransformGroup>
                    </RectangleGeometry.Transform>
                </RectangleGeometry>
            </Grid.Clip>
            <Grid
                x:Name="Page1ContentGrid">
                <Image
                    VerticalAlignment="Stretch"
                    HorizontalAlignment="Stretch"
                    Stretch="UniformToFill"
                    Source="http://bigbackground.com/wp-content/uploads/2013/07/tropical-beach-screensaver.jpg" />
            </Grid>
        </Grid>
        <Grid
            x:Name="Page2"
            Opacity="0">
            <Grid.Clip>
                <RectangleGeometry
                    Rect="0,0,80000,80000">
                    <RectangleGeometry.Transform>
                        <TransformGroup>
                            <TranslateTransform
                                x:Name="Page2ClipTranslateTransform" />
                            <RotateTransform
                                x:Name="Page2ClipRotateTransform" />
                        </TransformGroup>
                    </RectangleGeometry.Transform>
                </RectangleGeometry>
            </Grid.Clip>
            <Grid
                x:Name="Page2ContentGrid">
                <Image
                    x:Name="Page2SampleContentImage"
                    VerticalAlignment="Stretch"
                    HorizontalAlignment="Stretch"
                    Stretch="UniformToFill"
                    Source="http://www.photography-match.com/views/images/gallery/Tropical_Lagoon.jpg" />
            </Grid>
        </Grid>
        <Grid
            x:Name="TransitionGridContainer">
            <Grid
                x:Name="TransitionGrid"
                Opacity="0">
                <Grid.RenderTransform>
                    <CompositeTransform
                        x:Name="TransitionGridContainerTransform" />
                </Grid.RenderTransform>
                <Grid.Clip>
                    <RectangleGeometry
                        Rect="0,0,80000,80000">
                        <RectangleGeometry.Transform>
                            <TransformGroup>
                                <TranslateTransform
                                    x:Name="TransitionGridClipTranslateTransform" />
                                <RotateTransform
                                    x:Name="TransitionGridClipRotateTransform" />
                            </TransformGroup>
                        </RectangleGeometry.Transform>
                    </RectangleGeometry>
                </Grid.Clip>
                <Image
                    x:Name="TransitionImage"
                    Stretch="None" />
            </Grid>
        </Grid>
    </Grid>
</Page>

<强> C#

using System;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Media.Imaging;

namespace FlipControls
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            PreloadTransitionGridContentAsync();
        }

        private async Task PreloadTransitionGridContentAsync()
        {
            #region Waiting for page 2 content to load
            var bi = Page2SampleContentImage.Source as BitmapImage;

            if (bi.PixelWidth == 0)
            {
                bi.ImageFailed += (s, e) => new MessageDialog("Need a different sample image.").ShowAsync();
                bi.ImageOpened += (s, e) => PreloadTransitionGridContentAsync();
                return;
            }

            if (Page2ContentGrid.ActualWidth == 0)
            {
                SizeChangedEventHandler sizeChangedEventHandler = null;
                sizeChangedEventHandler = (s, e) =>
                {
                    PreloadTransitionGridContentAsync();
                    Page2ContentGrid.SizeChanged -= sizeChangedEventHandler;
                };

                Page2ContentGrid.SizeChanged += sizeChangedEventHandler;

                return;
            } 
            #endregion

            var rtb = new RenderTargetBitmap();
            await rtb.RenderAsync(Page2ContentGrid);
            TransitionImage.Source = rtb;
            await Task.Delay(40000);
        }

        private bool isCancellationRequested;

        private enum FlipDirections
        {
            Left,
            Right
        }

        private FlipDirections flipDirection;
        private Point manipulationStartPosition;
        private double rotationCenterX;
        private double rotationCenterY;

        private void ManipulationGrid_OnManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
        {
            if (TransitionImage.Source == null)
            {
                CancelManipulation(e);
                return;
            }

            manipulationStartPosition = e.Position;

            if (Page1.Opacity == 1)
            {
                flipDirection = FlipDirections.Left;
                Page2ClipTranslateTransform.X = ManipulationGrid.ActualWidth;
                Page2.Opacity = 1;
                TransitionGridClipTranslateTransform.X = -80000;
                TransitionGridContainerTransform.TranslateX = ManipulationGrid.ActualWidth;
                TransitionGrid.Opacity = .975;
            }
            else
            {
                if (manipulationStartPosition.X >= this.ManipulationGrid.ActualWidth / 2)
                {
                    // Can't flip left since there is no page after the current one
                    CancelManipulation(e);
                    return;
                }

                flipDirection = FlipDirections.Right;

                Page1.Opacity = 1;
            }
        }

        private void ManipulationGrid_OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            if (this.isCancellationRequested)
            {
                return;
            }

            if (flipDirection == FlipDirections.Left)
            {
                var w = this.ManipulationGrid.ActualWidth;
                var h = this.ManipulationGrid.ActualHeight;

                var cx = Math.Min(0, Math.Max(e.Position.X - w, -w));
                var cy = e.Cumulative.Translation.Y;
                var angle = (Math.Atan2(cx + manipulationStartPosition.Y - w, -cy) * 180 / Math.PI + +90) % 360;

                this.rotationCenterX = w + cx / 2;

                if (cy < 0)
                {
                    this.rotationCenterY = h;
                }
                else
                {
                    this.rotationCenterY = 0;
                }

                Page2ClipTranslateTransform.X = w + cx / 2;
                Page2ClipTranslateTransform.Y = -40000 + h / 2;
                Page2ClipRotateTransform.CenterX = this.rotationCenterX;
                Page2ClipRotateTransform.CenterY = this.rotationCenterY;
                Page2ClipRotateTransform.Angle = angle;

                TransitionGridClipTranslateTransform.X = -80000 - (cx / 2);
                TransitionGridClipTranslateTransform.Y = -40000 + h / 2;
                TransitionGridClipRotateTransform.CenterX = -cx / 2;
                TransitionGridClipRotateTransform.CenterY = this.rotationCenterY;
                TransitionGridClipRotateTransform.Angle = -angle;

                TransitionGridContainerTransform.TranslateX = w + cx;
                TransitionGridContainerTransform.CenterX = -cx / 2;
                TransitionGridContainerTransform.CenterY = this.rotationCenterY;
                TransitionGridContainerTransform.Rotation = 2 * angle;
            }
        }

        private void ManipulationGrid_OnManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
        {
            if (this.isCancellationRequested)
            {
                this.isCancellationRequested = false;
                return;
            }

            var w = this.ManipulationGrid.ActualWidth;
            var h = this.ManipulationGrid.ActualHeight;

            var sb = new Storyboard();
            AddAnimation(sb, Page2ClipTranslateTransform, "X", w / 2);
            AddAnimation(sb, Page2ClipRotateTransform, "CenterX", w / 2);
            AddAnimation(sb, Page2ClipRotateTransform, "Angle", 0);

            AddAnimation(sb, TransitionGridClipTranslateTransform, "X", -80000 + (w / 2));
            AddAnimation(sb, TransitionGridClipRotateTransform, "CenterX", w / 2);
            AddAnimation(sb, TransitionGridClipRotateTransform, "Angle", 0);

            AddAnimation(sb, TransitionGridContainerTransform, "TranslateX", 0);
            AddAnimation(sb, TransitionGridContainerTransform, "CenterX", w / 2);
            AddAnimation(sb, TransitionGridContainerTransform, "Rotation", 0);
            sb.Begin();
        }

        private static void AddAnimation(Storyboard sb, DependencyObject dob, string path, double to)
        {
            var da = new DoubleAnimation();
            Storyboard.SetTarget(da, dob);
            Storyboard.SetTargetProperty(da, path);
            da.To = to;
            da.Duration = TimeSpan.FromSeconds(.2);
            sb.Children.Add(da);
        }

        private void CancelManipulation(ManipulationStartedRoutedEventArgs e)
        {
            this.isCancellationRequested = true;
            e.Complete();
        }
    }
}

答案 3 :(得分:2)

对于图片 - 您只需使用ImageBrush并使用它填充具有所需几何图形的Path即可。对于任何更复杂的事情 - 使用RenderTargetBitmap.Render()将您的XAML转换为位图并返回答案1.

答案 4 :(得分:0)

我觉得需要说的是,对于“使用ImageBrush填充的路径”技术,基本上不可能使图像完全按照您想要的使用变换对齐,因为图像(图像画笔)内部的确切位置路径剪辑取决于路径的范围,包括Stroke。

因此,例如,如果您有贝塞尔曲线路径,则需要计算该贝塞尔曲线的实际范围,然后才能确定要应用于图像的精确缩放/平移变换。

中风似乎是无辜的,但是当你的多线路径中有一个锐角时,中风会形成尖锐的三角形!但也只是在一定程度上,因为在角度变得非常尖锐之后,三角形不再那么尖锐了!因此,您需要复制执行Stroke for Path的确切算法。

最后,我确实需要承认可以选择复制笔划的路径,所以有一个使用ImageBrush Fill,另一个没有但是有Stroke。