티스토리 뷰

반응형

OneSearch에 처음 플립뷰를 이용해서 이미지 뷰어를 만들었을 때.. 핀치 줌을 사용해서 이미지를 확대/축소를 하고 싶었는데.. 간단하게 처리가 되지 않았서 그냥 다음에 하지머..하고 넘어간적이 있었다.

얼마전, 다른 앱을 작업하다가 핀치 줌을 이용해야 하는 경우가 다시 발생해서 떡 본김에 제사 지낸다고, 그냥 만들었다. 음 물론 시간은 4-5시간 정도 걸린 것 같다.

 

0. 환경

Windows 10, Visual Studio 2015

 

1. MainPage.xaml


    x:Class="FlipViewSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:FlipViewSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
    xmlns:commons="using:FlipViewSample.Commons"
    mc:Ignorable="d">
    <Page.Resources>
        <DataTemplate x:Key="DataTemplate1">
            <ScrollViewer x:Name="scrollViewer" ZoomMode="Enabled"
                          HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
                          HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                          HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
                <Image Stretch="None" Source="{Binding PhotoUri}" Tag="{Binding PhotoUri}">
                    <interactivity:Interaction.Behaviors>
                        <commons:ImageBehavior ZoomScrollViewer="{Binding ElementName=scrollViewer}"/>
                    </interactivity:Interaction.Behaviors>
                </Image>
            </ScrollViewer>

        </DataTemplate>
    </Page.Resources>
    <Page.DataContext>
        <local:MainPageViewModel/>
    </Page.DataContext>

 

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <FlipView x:Name="flipView" ItemsSource="{Binding PhotoList}" ItemTemplate="{StaticResource DataTemplate1}" ManipulationMode="TranslateX"/>

    </Grid>
</Page>

 

FlipView에 ManipulationMode="TranslateX"를 지정하는 것이 중요하다. FilpView는 가로 방향의 제스처에만 반응하도록 만들어야 한다.

 

ScrollViewer에는 위에 굵은 글씨들의 내용을 꼭 추가해 줘야한다.

 

 

2. ImageBehavior.cs

    }
    {
        // Using a DependencyProperty as the backing store for ScrollViewer.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScrollViewerProperty =
            DependencyProperty.Register("ZoomScrollViewer", typeof (ScrollViewer), typeof (ImageBehavior),
                new PropertyMetadata(null));

        /// <summary>
        ///     중복실행 방지
        /// </summary>
        private bool _isWork;

        /// <summary>
        ///     중복실행 방지
        /// </summary>
        private readonly object _lock = new object();

        public ScrollViewer ZoomScrollViewer
        {
            get { return (ScrollViewer) GetValue(ScrollViewerProperty); }
            set { SetValue(ScrollViewerProperty, value); }
        }

        public void Attach(DependencyObject associatedObject)
        {
            if (!(associatedObject is Image)) return;
            var im = (Image) associatedObject;
            AssociatedObject = im;
            im.ImageOpened += Im_ImageOpened;

            if (ZoomScrollViewer == null) return;
            ZoomScrollViewer.SizeChanged += ZoomScrollViewer_SizeChanged;
        }

        public void Detach()
        {
            var im = (Image) AssociatedObject;
            im.ImageOpened -= Im_ImageOpened;
            if (ZoomScrollViewer == null) return;
            ZoomScrollViewer.SizeChanged += ZoomScrollViewer_SizeChanged;
        }

        public DependencyObject AssociatedObject { get; private set; }

        private void ZoomScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            SizeChanged();
        }

        /// <summary>
        ///     이미지가 열렸을 때 기본 크기 변경
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Im_ImageOpened(object sender, RoutedEventArgs e)
        {
            SizeChanged();
        }

        private void SizeChanged()
        {
            lock (_lock)
            {
                if (_isWork) return;
                _isWork = true;
            }
            if (ZoomScrollViewer == null) return;
            var im = (Image) AssociatedObject;

            //이미지 사이즈에 맞춰서 줌팩터 조정
            var w1 = Convert.ToSingle(ZoomScrollViewer.ViewportWidth/(im.ActualWidth + 40.0f));
            var h1 = Convert.ToSingle(ZoomScrollViewer.ViewportHeight/(im.ActualHeight + 40.0f));

            Debug.WriteLine("ZoomFactor w1={0}, h1={1}", w1, h1);
            var zoomFactor = Math.Min(w1, h1);
            if (Math.Abs(ZoomScrollViewer.ZoomFactor - zoomFactor) > 0)
            {
                ZoomScrollViewer.ChangeView(0, 0, Math.Min(w1, h1));
            }

            _isWork = false;
        }
    }

 

전체 소스는 첨부 파일을 참고한다.

 

 

3. 실행 화면

 

 

 

 

 

4. 이미지를 앱에서 표시할 때 가장 좋은 선택은 이미지의 경로를 문자열 만들고, 그 것을 Image.Source에 바인딩을 하는 것이 좋다.

 

 

FlipViewSample.zip

 

반응형
댓글