当缩放中心因地铁式应用程序中的捏合(缩放)或其他手势而发生变化时,如何在缩放画布对象时避免“跳跃”
我尝试存档的行为类似于预安装的win8地图应用的缩放行为。如果您执行捏合手势(放大或缩小),缩放中心将设置在手指之间的中间位置。如果抬起其中一根手指,将其放在另一个点上,您可以立即执行另一个缩放操作,缩放中心正确更改,无任何跳跃(画布中对象的UI坐标跳转)。
我正在尝试使用复合变换在大型Canvas对象(在C#WinRT应用程序中)上实现类似的行为。我想允许翻译和缩放,没有旋转(现在,也许我稍后会添加它):
我这样初始化,将缩放中心放在屏幕中心:
this.compositeTransform = new CompositeTransform();
this.compositeTransform.CenterX = this.mainPage.Width / 2.0;
this.compositeTransform.CenterY = this.mainPage.Height / 2.0;
this.innerCanvas.RenderTransform = compositeTransform;
然后我将使用操作delta事件来获取输入数据
private void InnerCanvas_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
this.compositeTransform.ScaleX *= e.Delta.Scale;
this.compositeTransform.ScaleY *= e.Delta.Scale;
this.compositeTransform.CenterX = e.Position.X;
this.compositeTransform.CenterY = e.Position.Y;
this.compositeTransform.TranslateX += e.Delta.Translation.X;
this.compositeTransform.TranslateY += e.Delta.Translation.Y;
}
只要我执行相同的手势,这就可以正常工作。当我执行捏合手势时,正确计算新中心。然而,改变缩放中心会导致突然跳跃,例如在捏动手势之后抬起其中一个手指时。当然,我只能为捏手势改变中心,但跳跃的问题仍然存在。这当然是合乎逻辑的,因为缩放适用于新的缩放中心。我还没想出办法,如何避免跳跃。由于比例值本身保持不变,因此必须可以使用相同的外观(不变的坐标)和更改的中心。
我目前的理由是,我必须以某种方式更改TranslateX和TranslateY坐标,以便以某种方式平衡新的中心点,即ui元素的当前屏幕坐标保持不变。像这样的东西(scaleTransform是一个ScaleTransform,它只获取缩放数据)......
Point reverseScaleTransform =
this.scaleTransform.Inverse.TransformPoint(new Point(e.Position.X,e.Position.Y));
this.compositeTransform.TranslateX += reverseScaleTransform.X - e.Position.X;
this.compositeTransform.TranslateY += reverseScaleTransform.Y - e.Position.Y;
但这也不起作用。整个事情似乎是平板电脑上的一个标准问题,但我没有找到解决方案,尽管搜索过多,也许我使用了错误的关键词。
答案 0 :(得分:2)
我终于想通了,如何通过手动转换解决问题,而不是使用ScrollViewer。
TranslateTransform tmpTranslate = new TranslateTransform();
private void InnerCanvas_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
//Transform world space into local space (origin: Scale center from the last manipulation event)
this.tmpTranslate.X = this.compositeTransform.CenterX;
this.tmpTranslate.Y = this.compositeTransform.CenterY;
Point center = this.compositeTransform.Inverse.TransformPoint(e.Position);
Point localPoint = tmpTranslate.Inverse.TransformPoint(center);
//Now scale the point in local space
localPoint.X *= this.compositeTransform.ScaleX;
localPoint.Y *= this.compositeTransform.ScaleY;
//Transform local space into world space again
Point worldPoint = tmpTranslate.TransformPoint(localPoint);
//Take the actual scaling...
Point distance = new Point(
worldPoint.X - center.X,
worldPoint.Y - center.Y);
//...amd balance the jump of the changed scaling origin by changing the translation
this.compositeTransform.TranslateX += distance.X;
this.compositeTransform.TranslateY += distance.Y;
//Also set the scaling values themselves, especially set the new scale center...
this.compositeTransform.ScaleX *= e.Delta.Scale;
this.compositeTransform.ScaleY *= e.Delta.Scale;
this.compositeTransform.CenterX = center.X;
this.compositeTransform.CenterY = center.Y;
//And consider a translational shift
this.compositeTransform.TranslateX += e.Delta.Translation.X;
this.compositeTransform.TranslateY += e.Delta.Translation.Y;
}
答案 1 :(得分:0)
我建议查看示例windows 8 XAML scrolling, panning, and zooming sample。
已经为您实现了缩放,只需使用滚动查看器打开缩放。这符合您的要求吗?
答案 2 :(得分:0)
如果我们只是添加
distance.x = (currentcenter.x - previouscenter.x) * (scalefactortillnow - 1)
类似地
distance.y = (currentcenter.y - previouscenter.y) * (scalefactortillnow - 1)
和
composite.translatex += distance.x;
composite.translatey += distance.y;
然后由于中心变化而补偿跳跃就足够了。 我亲自面对这个问题,发现这很有效。