5

メトロ スタイル アプリでのピンチ (ズーム) やその他のジェスチャによってスケーリングの中心が変化したときに、キャンバス オブジェクトのスケーリング中に「ジャンプ」を回避するにはどうすればよいですか?

アーカイブしようとしている動作は、プレインストールされている win8 マップ アプリのズーム動作に似ています。ピンチ ジェスチャ (ズーム インまたはズーム アウト) を実行すると、スケーリングの中心が指の中間に設定されます。指の 1 本を離して別のポイントに置くと、すぐに別のズーム操作を実行できます。ズームの中心は、ジャンプなしで正しく変更されます (キャンバス内のオブジェクトの 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;

次に、操作デルタ イベントを使用して入力データを取得します。

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;                      
}

同じジェスチャを実行する限り、これは正しく機能します。ピンチ ジェスチャを実行すると、新しい中心が正しく計算されます。ただし、ズームの中心を変更すると、たとえばピンチ ジェスチャの後に 1 本の指を離すと、突然ジャンプします。もちろん、ピンチのジェスチャーだけ中心を変えることはできますが、ジャンプの問題は残ります。スケーリングは新しいスケーリング センターで機能するため、これはもちろん論理的です。ジャンプを回避する方法がわかりません。スケール値自体は一定のままなので、中心を変更しても同じ外観 (変更されていない座標) を持つことが可能である必要があります。

私の現在の推論は、新しい中心点のバランスをとるために、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;

しかし、これもうまくいきません。全体がタブレットの標準的な問題のようですが、過度の検索にもかかわらず解決策が見つかりませんでした。間違ったキーワードを使用している可能性があります。

4

3 に答える 3

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;                                    
    }
于 2012-12-29T23:37:47.660 に答える
0

サンプルウィンドウ8XAMLのスクロール、パン、およびズームのサンプルを確認することをお勧めします。

ズームはすでに実装されています。ズームをオンにしてスクロールビューアを使用するだけです。これはあなたの要件を満たしていますか?

于 2012-12-23T15:15:06.187 に答える
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;

その場合、中心の変化によるジャンプを補正するのに十分です。私は個人的に問題に直面し、これが機能することを発見しました。

于 2015-09-03T08:54:45.470 に答える