#742&743 –使用触摸事件旋转和缩放控件

原文地址:https://wpf.2000things.com/2013/01/25/742-using-touch-manipulation-events-to-rotate-an-element/

在上一篇中,我们使用触摸事件移动控件,我们同样可以用类似的方法来旋转和缩放控件。

这次我们在ManipulationDelta 事件处理函数中同时对控件支持位移、旋转和缩放。事件参数中的ManipulationDelta 实例会提供位移矢量、旋转角度和缩放倍数。

下面是XAML代码:

<Canvas Name="canvMain" Background="Transparent">
    <Image Source="JamesII.jpg" Width="100"
           IsManipulationEnabled="True"
           RenderTransform="{Binding ImageTransform}"
           ManipulationStarting="Image_ManipulationStarting" ManipulationDelta="Image_ManipulationDelta"/>
</Canvas>

ManipulationDelta 事件处理函数中通过矩阵同时处理对控件的位移、旋转和缩放。

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
 
        ImageTransform = new MatrixTransform();
    }
 
    private MatrixTransform imageTransform;
    public MatrixTransform ImageTransform
    {
        get { return imageTransform; }
        set
        {
            if (value != imageTransform)
            {
                imageTransform = value;
                RaisePropertyChanged("ImageTransform");
            }
        }
    }
 
    private void Image_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
    {
        // Ask for manipulations to be reported relative to the canvas
        e.ManipulationContainer = canvMain;
    }
 
    private void Image_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
        ManipulationDelta md = e.DeltaManipulation;
        Vector trans = md.Translation;  // 获得位移矢量
        double rotate = md.Rotation;  // 获得旋转角度
        Vector scale = md.Scale;  // 获得缩放倍数

        Matrix m = imageTransform.Matrix;
 
        // Find center of element and then transform to get current location of center
        FrameworkElement fe = e.Source as FrameworkElement;
        Point center = new Point(fe.ActualWidth / 2, fe.ActualHeight / 2);
        center = m.Transform(center);  // 转换为矩阵缩放和旋转的中心点
 
        // Update matrix to reflect translation/rotation
        m.Translate(trans.X, trans.Y);  // 移动
        m.RotateAt(rotate, center.X, center.Y);  // 旋转
        m.ScaleAt(scale.X, scale.Y, center.X, center.Y);  // 缩放
 
        imageTransform.Matrix = m;
        RaisePropertyChanged("ImageTransform");
 
        e.Handled = true;
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    private void RaisePropertyChanged(string prop)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
    }
}

通过这篇文章和上篇文章,我们可以让控件随手指移动、放大和旋转。但是如果我们仅仅只想控件在水平或者垂直某一个方向上移动,又或者只想控件旋转或者缩放,而没有其他操作,我们可以在ManipulationStarting 事件的处理函数中设置ManipulationStartingEventArgs.Mode 属性来控制控件随手指变换的模式。

ManipulationStartingEventArgs.Mode属性的值是一个ManipulationModes 类型的枚举。枚举成员如下:

 -  None 所有操作都不会发生

 -  Rotate 只有旋转操作

 -  Scale 只有缩放操作

 -  Translate 仅支持水平和垂直移动

 - TranslateX 仅支持水平移动

 - TranslateY 仅支持垂直移动

 - All 所有操作都支持(移动、缩放和旋转)

默认情况下它的值是All。下面的示例代码中,表示仅支持水平移动。

private void Image_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
{
    // Ask for manipulations to be reported relative to the canvas
    e.ManipulationContainer = canvMain;
 
    // 仅支持水平移动
    e.Mode = ManipulationModes.TranslateX;
}

如果想要支持其中的多种触摸操作,可以使用于运算符(|)计算然后赋值:

// 支持移动和缩放
e.Mode = ManipulationModes.Translate | ManipulationModes.Scale;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个使用TextureView实现多点触摸控制的例子,包括移动缩放旋转: ```java public class MultiTouchTextureView extends TextureView implements TextureView.SurfaceTextureListener { private float mPosX, mPosY; private float mLastTouchX, mLastTouchY; private float mScaleFactor = 1.f; private float mLastGestureX, mLastGestureY; private float mRotationDegrees = 0.f; public MultiTouchTextureView(Context context) { this(context, null, 0); } public MultiTouchTextureView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MultiTouchTextureView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setSurfaceTextureListener(this); } @Override public boolean onTouchEvent(MotionEvent event) { // Let the ScaleGestureDetector inspect all events. mScaleDetector.onTouchEvent(event); final int action = event.getAction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { final float x = event.getX(); final float y = event.getY(); mLastTouchX = x; mLastTouchY = y; break; } case MotionEvent.ACTION_MOVE: { final float x = event.getX(); final float y = event.getY(); // Only move if the ScaleGestureDetector isn't processing a gesture. if (!mScaleDetector.isInProgress()) { final float dx = x - mLastTouchX; final float dy = y - mLastTouchY; mPosX += dx; mPosY += dy; invalidate(); } mLastTouchX = x; mLastTouchY = y; break; } case MotionEvent.ACTION_UP: { break; } case MotionEvent.ACTION_CANCEL: { break; } case MotionEvent.ACTION_POINTER_UP: { break; } } return true; } private ScaleGestureDetector mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); // Don't let the object get too small or too large. mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); invalidate(); return true; } }); @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { // Setup default size and position mPosX = width / 2.f; mPosY = height / 2.f; mLastGestureX = width / 2.f; mLastGestureY = height / 2.f; // Set the aspect ratio of the TextureView int aspectRatio = height > width ? height / width : width / height; setAspectRatio(aspectRatio); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // Update default size and position when the TextureView size changes mPosX = width / 2.f; mPosY = height / 2.f; mLastGestureX = width / 2.f; mLastGestureY = height / 2.f; } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); // Move the canvas to the center of the TextureView canvas.translate(mPosX, mPosY); // Scale the canvas based on the scale factor canvas.scale(mScaleFactor, mScaleFactor); // Rotate the canvas based on the rotation degrees canvas.rotate(mRotationDegrees); // Draw your content here // ... canvas.restore(); } } ``` 这个例子中,我们使用了TextureView作为视图容器,通过触摸事件实现多点触摸控制。在onTouchEvent方法中,我们处理了移动的逻辑,通过ScaleGestureDetector处理缩放的逻辑。在onDraw方法中,我们先将画布移动到TextureView的中心点,然后根据移动缩放旋转的参数对画布进行变换。你可以在onDraw方法中添加你自己的绘制逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值