画布中控件的缩放移动还原

效果展示

在这里插入图片描述可以兼容矢量图

xaml:

<UserControl x:Class="CZ_UI_Templates.EntryDataBase.ZoomImageCanvas"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:CZ_UI_Templates.EntryDataBase"
             mc:Ignorable="d" x:Name="_WorkView">
    <UserControl.Resources>
        <Style TargetType="Button">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Cursor" Value="Hand"/>
                    <Setter Property="Background" Value="Transparent"/>
                    <Setter Property="Foreground" Value="{StaticResource TI_Color1}"/>
                </Trigger>
                <Trigger Property="IsMouseOver" Value="False">
                    <Setter Property="Background" Value="Transparent"/>
                    <Setter Property="Foreground" Value="{StaticResource CZ_FontColor}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
            <Border Name="Border" CornerRadius="6" Background="Transparent" BorderBrush="Transparent" BorderThickness="0">
                <WrapPanel VerticalAlignment="Center" HorizontalAlignment="Stretch">
                    <TextBlock Name="IcoText"
                               TextAlignment="Center"
                               HorizontalAlignment="Center"
                               FontFamily="{DynamicResource IconMoonFontFamily}"
                               Text="{TemplateBinding Content}"
                               Margin="5,0,5,0">
                    </TextBlock>
                </WrapPanel>
            </Border>
        </ControlTemplate>
    </UserControl.Resources>
    <Canvas Margin="1" ClipToBounds="True">
        <Border x:Name="border" Canvas.Top="0" Canvas.Right="0"
                BorderBrush="Transparent" Panel.ZIndex="1"
                MinHeight="30" Height="auto" Width="auto"
                Background="White"
                BorderThickness="3"                
                CornerRadius="5">
            <WrapPanel Margin="3">
                <Button x:Name="btn1" Margin="7 0 5 0" Template="{StaticResource ButtonTemplate}"
                        Background="Transparent" Tag="-0.1"
                        BorderThickness="0" Content="&#xed5c;" Click="Button_Click"/>
                <TextBlock Name="m_ProportionContent" Width="auto" Text="{Binding m_ProportionContentValue}" TextAlignment="Center"/>
                <Button x:Name="btn2" Margin="6 0 5 0" Template="{StaticResource ButtonTemplate}"
                        Background="Transparent" Tag="0.1"
                        BorderThickness="0" Content="&#xed5d;" Click="Button_Click"/>
                <Border BorderBrush="{StaticResource CZ_FontColor}" BorderThickness="1" Width="0.5"/>
                <Button Content="&#xed5e;" Margin="2" Template="{StaticResource ButtonTemplate}"
                        Background="Transparent" Tag="1"
                        BorderThickness="0" Click="Button_Click"/>
            </WrapPanel>
        </Border>
        <Canvas Background="White"
            x:Name="FirstBase"
            MouseWheel="Base_MouseWheel"
            MouseMove="FirstBase_MouseMove"
            MouseRightButtonDown="Base_MouseRightButtonDown"
            MouseRightButtonUp="Base_MouseRightButtonUp"
            ClipToBounds="True"
            Width="{Binding ElementName=_WorkView, Path=ActualWidth}"
            Height="{Binding ElementName=_WorkView, Path=ActualHeight}">
            <Canvas Focusable="True"
                Background="Transparent"
                x:Name="SecondBase" 
                Width="{Binding ElementName=_WorkView, Path=ActualWidth}"
                Height="{Binding ElementName=_WorkView, Path=ActualHeight}"
                Canvas.Left="0"
                Canvas.Top="0" >
                <DockPanel x:Name="View"  
                      Canvas.Left="0"
                      Canvas.Top="0"
                      Background="White"
                      Height="{Binding ElementName=SecondBase, Path=ActualHeight}"
                      Width="{Binding ElementName=SecondBase, Path=ActualWidth}">
                </DockPanel>
                <Canvas.RenderTransform>
                    <TransformGroup x:Name="transGrp">
                        <ScaleTransform x:Name="sfr" ScaleX="1" ScaleY="1" CenterX="00" CenterY="00"/>
                        <TranslateTransform x:Name="tlt"/>
                        <MatrixTransform x:Name="Matfr"/>
                    </TransformGroup>
                </Canvas.RenderTransform>
            </Canvas>
        </Canvas>
    </Canvas>
</UserControl>

后台

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace CZ_UI_Templates.EntryDataBase
{
    /// <summary>
    /// ZoomImageCanvas.xaml 的交互逻辑
    /// </summary>
    public partial class ZoomImageCanvas : UserControl, INotifyPropertyChanged
    {
        /*Canvas放大缩小相关*/
        bool View_isMouseRightBtnDown = false;
        Point View_lastMousePt;
        Point lastCenterPoint;
        double View_originOffsetX = 0, View_originOffsetY = 0;
        /// <summary>
        /// 是否拖动状态
        /// </summary>
        public bool m_View_isMouseRightBtnDown
        {
            get => View_isMouseRightBtnDown;
            set
            {
                View_isMouseRightBtnDown = value;

                ///右键拖动时卡顿的最终解决方案,在拖动时,启用cacheMode,拖动结束后,关闭cacheMode,因为在拖动待连线的模块时如果开启CacheMode,将占用大量内存
                if (value)
                {
                    SecondBase.CacheMode = new BitmapCache() { EnableClearType = false, RenderAtScale = 3, SnapsToDevicePixels = false };
                }
                else
                {
                    SecondBase.CacheMode = null;
                }
            }
        }
        //用来记录窗口放大率
        private string _ProportionContent;
        public string m_ProportionContentValue
        {
            get => _ProportionContent;
            set
            {
                value = string.Format("{0}%", (m_Proportion * 100)).Split('.')[0];
                _ProportionContent = value;
                OnPropertyChanged("m_ProportionContentValue");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private double _Proportion;
        public double m_Proportion
        {
            get => _Proportion;
            set
            {
                _Proportion = value;
                m_ProportionContentValue = "";
            }
        }
        public ZoomImageCanvas()
        {
            InitializeComponent();
            m_Proportion = 1;
            DataContext = this;
        }
        public void SetUIElement(UIElement uIElement)
        {
            Canvas.SetTop(uIElement, 0);
            Canvas.SetLeft(uIElement, 0);
            if (uIElement != null)            
            {            
                this.View.Children.Add(uIElement);                
            }            
        }
        #region 第一个内层Canvas事件处理
        private void Base_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            //ctrl键按下+鼠标滚动 缩放画面
            if ((Keyboard.Modifiers & (ModifierKeys.Control)) == (ModifierKeys.Control))
            {   //ctrl键按下
                if (e.Delta > 0)
                {
                    m_ZoomIn(Mouse.GetPosition(FirstBase));
                }
                else
                {
                    m_ZoomOut(Mouse.GetPosition(FirstBase));
                }
                e.Handled = true;
                return;
            }
        }

        private void FirstBase_MouseMove(object sender, MouseEventArgs e)
        {
            Point point = Mouse.GetPosition(this.FirstBase);
            if (m_View_isMouseRightBtnDown)
            {
                Point SBoffsetA = SecondBase.TranslatePoint(new Point(0, 0), FirstBase);//secondbase的左上角点
                Point SBoffsetB = SecondBase.TranslatePoint(new Point(SecondBase.ActualWidth, SecondBase.ActualHeight), FirstBase);//secondbase的右下角点
                if ((point.X > View_lastMousePt.X && SBoffsetA.X < FirstBase.ActualWidth * 0.5)
                    || (point.X < View_lastMousePt.X && SBoffsetB.X > FirstBase.ActualWidth * 0.5))
                {
                    double x = point.X - View_lastMousePt.X;
                    double secondLeft = Canvas.GetLeft(SecondBase);
                    Canvas.SetLeft(SecondBase, secondLeft + x);
                    View_originOffsetX += x;
                    lastCenterPoint.X -= x;
                }
                if ((point.Y > View_lastMousePt.Y && SBoffsetA.Y < FirstBase.ActualHeight * 0.5)
                    || (point.Y < View_lastMousePt.Y && SBoffsetB.Y > FirstBase.ActualHeight * 0.5))
                {
                    double y = point.Y - View_lastMousePt.Y;
                    double secondTop = Canvas.GetTop(SecondBase);
                    Canvas.SetTop(SecondBase, secondTop + y);
                    View_originOffsetY += y;
                    lastCenterPoint.Y -= y;
                }
                View_lastMousePt = point;
                e.Handled = true;
            }
            else
            {
                View_lastMousePt = point;
            }
        }

        private void Base_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            m_View_isMouseRightBtnDown = true;
            Mouse.OverrideCursor = Cursors.ScrollAll;
        }

        private void Base_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            Mouse.OverrideCursor = null;
            m_View_isMouseRightBtnDown = false;
        }
        #endregion
        #region 公共方法
        private void m_ZoomIn(Point mousePos)
        {
            if (sfr.ScaleX < 5)
            {
                mousePos.X -= View_originOffsetX;
                mousePos.Y -= View_originOffsetY;
                //原有中心点
                Point untransformedOldCenter = new Point(this.sfr.CenterX, this.sfr.CenterY);
                Point transformedOldCenter = this.sfr.Transform(untransformedOldCenter);
                //新中心点
                Point untransformedNewCenter = this.SecondBase.RenderTransform.Inverse.Transform(mousePos);
                Point transformedNewCenter = mousePos;
                //位置修正
                double adjustX = transformedNewCenter.X - transformedOldCenter.X -
                                untransformedNewCenter.X + untransformedOldCenter.X;
                double adjustY = transformedNewCenter.Y - transformedOldCenter.Y -
                                untransformedNewCenter.Y + untransformedOldCenter.Y;
                //更新
                this.tlt.X = adjustX;
                this.tlt.Y = adjustY;
                sfr.CenterX = untransformedNewCenter.X;
                sfr.CenterY = untransformedNewCenter.Y;

                sfr.ScaleX = sfr.ScaleX * 1.10;
                sfr.ScaleY = sfr.ScaleY * 1.10;
                m_Proportion = sfr.ScaleX;
            }
        }
        private void m_ZoomOut(Point mousePos)
        {
            double scaled_SecondBaseWidth = SecondBase.ActualWidth * sfr.ScaleX;
            if (scaled_SecondBaseWidth > FirstBase.ActualWidth * 0.2)
            {
                mousePos.X -= View_originOffsetX;
                mousePos.Y -= View_originOffsetY;
                //原有中心点
                Point untransformedOldCenter = new Point(this.sfr.CenterX, this.sfr.CenterY);
                Point transformedOldCenter = this.sfr.Transform(untransformedOldCenter);
                //新中心点
                Point untransformedNewCenter = this.SecondBase.RenderTransform.Inverse.Transform(mousePos);
                Point transformedNewCenter = mousePos;
                //位置修正
                double adjustX = transformedNewCenter.X - transformedOldCenter.X -
                                untransformedNewCenter.X + untransformedOldCenter.X;
                double adjustY = transformedNewCenter.Y - transformedOldCenter.Y -
                                untransformedNewCenter.Y + untransformedOldCenter.Y;
                //更新
                this.tlt.X = adjustX;
                this.tlt.Y = adjustY;
                sfr.CenterX = untransformedNewCenter.X;
                sfr.CenterY = untransformedNewCenter.Y;

                sfr.ScaleX = sfr.ScaleX * 0.90;
                sfr.ScaleY = sfr.ScaleY * 0.90;
                m_Proportion = sfr.ScaleX;
            }
        }
        /// <summary>
        /// 视图还原
        /// </summary>
        public void ViewDefault()
        {
            View_originOffsetX = 0;
            View_originOffsetY = 0;
            sfr.ScaleX = 1;
            sfr.ScaleY = 1;
            tlt.X = 0;
            tlt.Y = 0;
            sfr.CenterX = 0;
            sfr.CenterY = 0;
            Canvas.SetLeft(SecondBase, 0);
            Canvas.SetTop(SecondBase, 0);
            lastCenterPoint = new Point(this.ActualWidth / 2, this.ActualHeight / 2);
            m_Proportion = sfr.ScaleX;
        }
        #endregion
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;
            if (Convert.ToDouble(button.Tag) == 1)
            {
                ViewDefault();
            }
            else
            {
                Point point = new Point() { X = this.ActualWidth / 2, Y = this.ActualHeight / 2 };
                if (Convert.ToDouble(button.Tag) > 0)
                {
                    m_ZoomIn(point);
                }
                else
                {
                    m_ZoomOut(point);
                }
            }
        }
    }
}

资源地址:https://download.csdn.net/download/qq_34581845/85060039

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android实现控件缩放移动功能,可以通过自定义控件并重写其onTouchEvent()方法来实现。具体步骤如下: 1. 在自定义控件,实现GestureDetector.OnGestureListener接口和ScaleGestureDetector.OnScaleGestureListener接口,用于监听手势事件。 2. 在onTouchEvent()方法,将MotionEvent对象传递给GestureDetector和ScaleGestureDetector对象,分别监听手势事件。 3. 在GestureDetector的onScroll()方法,处理手指拖动事件,计算控件移动的距离,并将其应用到控件上。 4. 在ScaleGestureDetector的onScale()方法,处理缩放手势事件,计算控件缩放比例,并将其应用到控件上。 5. 需要注意的是,缩放功能需要在控件的父布局开启clipChildren属性,以保证控件可以在缩放不会超出父布局的边界。 示例代码如下: ```java public class ZoomView extends View implements GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener { private GestureDetector mGestureDetector; private ScaleGestureDetector mScaleGestureDetector; private float mScaleFactor = 1.0f; private float mLastTouchX; private float mLastTouchY; private float mPosX; private float mPosY; public ZoomView(Context context) { super(context); mGestureDetector = new GestureDetector(context, this); mScaleGestureDetector = new ScaleGestureDetector(context, this); } @Override public boolean onTouchEvent(MotionEvent motionEvent) { mGestureDetector.onTouchEvent(motionEvent); mScaleGestureDetector.onTouchEvent(motionEvent); final int action = motionEvent.getAction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { final float x = motionEvent.getX(); final float y = motionEvent.getY(); mLastTouchX = x; mLastTouchY = y; break; } case MotionEvent.ACTION_MOVE: { final float x = motionEvent.getX(); final float y = motionEvent.getY(); final float dx = x - mLastTouchX; final float dy = y - mLastTouchY; mPosX += dx; mPosY += dy; invalidate(); mLastTouchX = x; mLastTouchY = y; break; } } return true; } @Override public boolean onScale(ScaleGestureDetector scaleGestureDetector) { mScaleFactor *= scaleGestureDetector.getScaleFactor(); mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); invalidate(); return true; } @Override public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) { return true; } @Override public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) { } @Override public boolean onDown(MotionEvent motionEvent) { return true; } @Override public void onShowPress(MotionEvent motionEvent) { } @Override public boolean onSingleTapUp(MotionEvent motionEvent) { return true; } @Override public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float distanceX, float distanceY) { mPosX -= distanceX; mPosY -= distanceY; invalidate(); return true; } @Override public void onLongPress(MotionEvent motionEvent) { } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.scale(mScaleFactor, mScaleFactor); canvas.translate(mPosX / mScaleFactor, mPosY / mScaleFactor); // 绘制控件内容 canvas.restore(); } } ``` 在该示例,我们重写了onTouchEvent()方法,使用GestureDetector和ScaleGestureDetector对象分别监听拖动事件和缩放事件。在onScale()方法,我们计算了控件缩放比例,并在onScroll()方法计算了控件移动距离。最后,在onDraw()方法,我们将缩放移动的变换应用到画布上,然后在画布上绘制控件的内容。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值