首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我应该使用Xamarin表单的哪些功能来实现"3D“旋转,比如Instagram。

我应该使用Xamarin表单的哪些功能来实现"3D“旋转,比如Instagram。
EN

Stack Overflow用户
提问于 2017-04-30 23:45:48
回答 2查看 388关注 0票数 0

Instagram在应用程序的某些部分在用户之间切换时使用3D旋转,如下所示。

我一直在试验Xamarin的形式

  • 转换
  • 动画
  • Skia Sharp

但一直无法在Xamarin上重现这一切。在Xamarin表单上获得全屏旋转的正确技术是什么?

EN

回答 2

Stack Overflow用户

发布于 2017-04-30 23:57:31

您将不得不求助于自定义呈现器,并在C#:https://github.com/katleta3000/RotateController中实现类似的东西(这个示例在Swift中,可能还有类似的东西存在于Android中)。

据我所知,纯的Xamarin形式是不可能的。

这是提供的示例在C#中的样子(注意:我还没有测试结果,因此在下面的代码中有两个TODO):

代码语言:javascript
复制
// Example Swift code licensed by MIT license. Converted to C#.
// Original author: katleta3000

using System;
using CoreAnimation;
using UIKit;

namespace MyProject.iOS
{
    public enum RotationDirection : int
    {
        Right = 0, 
        Left
    }

    public enum RotationType : int
    {
        Push = 0,
        Pop
    }

    class FCBlackBackgroundView : UIView
    {

    }

    class FCRotateLayer : CALayer
    {
    }

    public class RotatingController : UINavigationController
    {
        public void PushViewController(UIViewController controller, RotationDirection rotateDirection) {
            Perform3DRotate(RotationType.Push, rotateDirection, controller);
        }

        public void PopViewController(RotationDirection rotateDirection) {
            Perform3DRotate(RotationType.Pop, rotateDirection, null);
        }

        // MARK: - private

        private void Perform3DRotate(RotationType type, RotationDirection rotateDirection, UIViewController controller) {
            var layer = RotationLayer();

            var cube = CubeTransform(rotateDirection, layer: layer);

            if (type == RotationType.Push) {
                this.PushViewController(controller, animated: false);
            } else if (type == RotationType.Pop) {
                this.PopViewController(animated: false);
            }
            layer.AddSublayer(LayerFromView(this.View, transform: cube));

            this.View.AddSubview(BackgroundView(UIColor.White));

            this.View.Layer.AddSublayer(layer);

            layer.AddAnimation(RotationAnimation(rotateDirection), "rotate");

        }

        private CATransform3D CubeTransform(RotationDirection rotateDirection, CALayer layer)
        {
            var cube = CATransform3D.MakeTranslation(0, 0, 0);

            layer.AddSublayer(LayerFromView(this.View, transform: cube));

            cube.Rotate(Radians(90), 0, 1, 0);

            cube.Translate(CubeSize(), 0, 0);

            if (rotateDirection == RotationDirection.Left) {
                cube.Rotate(Radians(90), 0, 1, 0);

                cube.Translate(CubeSize(), 0, 0);

                cube.Rotate(Radians(90), 0, 1, 0);

                cube.Translate(CubeSize(), 0, 0);

            }
            return cube;

        }

        private FCRotateLayer RotationLayer()
        {
            FCRotateLayer layer = new FCRotateLayer();

            layer.Frame = this.View.Frame;

            layer.AnchorPoint = new CoreGraphics.CGPoint(0.5, 0.5);

            CATransform3D transform = CATransform3D.Identity;

            transform.m34 = 1.0f / -750;

            layer.SublayerTransform = transform;

            return layer;

        }

        private CAAnimation RotationAnimation(RotationDirection direction) 
        {
            CATransaction.Flush();

            var animationGroup = new CAAnimationGroup();

            animationGroup.Duration = 0.4;

            CABasicAnimation rotation = null;
            CABasicAnimation translationX = null;

            if (direction == RotationDirection.Right) {
                rotation = CABasicAnimation.FromKeyPath("sublayerTransform.rotation.y");

                rotation.To = FromObject(Radians(-90));

                translationX = CABasicAnimation.FromKeyPath("sublayerTransform.translation.x");

                translationX.To = FromObject(-TranslationForAnimation());

            }
            else if (direction == RotationDirection.Left) {
                rotation = CABasicAnimation.FromKeyPath("sublayerTransform.rotation.y");

                rotation.To = FromObject(Radians(90));

                translationX = CABasicAnimation.FromKeyPath("sublayerTransform.translation.x");

                translationX.To = FromObject(TranslationForAnimation());

            }

            var translationZ = CABasicAnimation.FromKeyPath("sublayerTransform.translation.z");

            translationZ.To = FromObject(-TranslationForAnimation());

            animationGroup.Animations = new CAAnimation[] { rotation, translationX, translationZ };

            animationGroup.FillMode = CoreAnimation.CAFillMode.Forwards; //TODO: maybe convert nsstring to string

            animationGroup.RemovedOnCompletion = false;

            //TODO: unsubscribe necessary?
            animationGroup.AnimationStopped += (sender, e) =>
            {
                var layers = this.View.Layer.Sublayers;
                if (layers != null) {
                    foreach (var layer in layers) {
                        if (layer is FCRotateLayer) {
                            layer.RemoveFromSuperLayer();
                        }
                    }
                }
                foreach(var view in this.View.Subviews) {
                    if (view is FCBlackBackgroundView) {
                        view.RemoveFromSuperview();
                    }
                }
            };

            animationGroup.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut);

            return animationGroup;
        }

        private CALayer LayerFromView(UIView view) {
            var rect = CoreGraphics.CGRect.FromLTRB(0, 0, this.View.Bounds.Size.Width, this.View.Frame.Size.Height);

            CALayer imageLayer = new CALayer();

            imageLayer.AnchorPoint = new CoreGraphics.CGPoint(1, 1);

            imageLayer.Frame = rect;
            UIGraphics.BeginImageContextWithOptions(view.Frame.Size, false, UIScreen.MainScreen.Scale);
            var context = UIGraphics.GetCurrentContext();
            if (context != null) {
                view.Layer.RenderInContext(context);
            }
            UIImage image = UIGraphics.GetImageFromCurrentImageContext();

            UIGraphics.EndImageContext();

            imageLayer.Contents = image.CGImage;
            return imageLayer;
        }

        private CALayer LayerFromView(UIView view, CATransform3D transform) {
            var layer = LayerFromView(view);

            layer.Transform = transform;
            return layer;
        }

        private FCBlackBackgroundView BackgroundView(UIColor color)
        {
            var view = new FCBlackBackgroundView
            {
                Frame = this.View.Frame
            };

            view.BackgroundColor = color;
            return view;
        }

        private float Radians(float degrees) {
            return degrees * (float)Math.PI / 180;
        }

        private nfloat TranslationForAnimation() {
            return CubeSize() / 2;
        }

        private nfloat CubeSize() {
            return UIScreen.MainScreen.Bounds.Width;
        }
    }
}
票数 1
EN

Stack Overflow用户

发布于 2017-05-01 03:10:13

下面是链接的快速控制器的C#版本。有些事我无法从斯威夫特翻译过来。如果任何人都能验证/思考数字转换,那就太好了。

代码语言:javascript
复制
using CoreAnimation;
using CoreGraphics;
using UIKit;


namespace hackettyHack
{
    public enum RotationDirection //int
    {
        // case Right = 0, Left
        Right,
        Left
    }
    public enum RotationType //int
    {
        // case Push = 0, Pop   }
        Push,
        Pop
    }


    class FCBlackBackgroundView : UIView
    {

    }

    class FCRotateLayer : CALayer
    {
    }

    public class RotatingController : UINavigationController
    {
        public void PushViewController(UIViewController controller, RotationDirection rotateDirection)
        {
            Perform3DRotate(RotationType.Push, rotateDirection, controller);
        }
        public void PopViewController(UIViewController controller, RotationDirection rotateDirection)
        {
            Perform3DRotate(RotationType.Pop, rotateDirection, controller);
        }

        void Perform3DRotate(RotationType rotationType, RotationDirection rotateDirection, UIViewController v)
        {
            var layer = RotationLayer();

            var cube = CubeTransform(rotateDirection, layer);

            switch (rotationType)
            {
                case RotationType.Pop:
                    this.PopViewController(animated: false);
                    break;
                case RotationType.Push:
                    this.PushViewController(this, animated: false); //todo: make sure the SWIFT line below for controller! means THIS
                                                                    // self.pushViewController(controller!, animated: false)
                    break;
                default:
                    break;
            }

            layer.AddSublayer(LayerFromView(this.View, cube));

            this.View.AddSubview(BackgroundView(UIColor.White));

            this.View.Layer.AddSublayer(layer);

            layer.AddAnimation(RotationAnimation(rotateDirection), forkey: "rotate");//FIXME  parameter
        }

        CATransform3D CubeTransform(RotationDirection rotateDirection, CALayer layer)
        {
            var cube = CATransform3D.MakeTranslation(0, 0, 0);//FIXME and all below

            layer.AddSublayer(LayerFromView(this.View, transform: cube);

            cube = CATransform3D.Rotate(cube, CGFloat(radians(90)), 0, 1, 0);

            cube = CATransform3D.Translate(cube,CubeSize(), 0, 0);
            if (rotateDirection == RotationDirection.Left)
            {
                cube = CATransform3D.Rotate(cube, CGFloat(radians(90)), 0, 1, 0);

                cube = CATransform3D.Translate(cube, CubeSize(), 0, 0);

                cube = CATransform3D.Rotate(cube, CGFloat(radians(90)), 0, 1, 0);

                cube = CATransform3D.Translate(cube, CubeSize(), 0, 0);

            }
            return cube;
        }

        FCRotateLayer RotationLayer()
        {
            var layer = new FCRotateLayer();

            layer.Frame = this.View.Frame;

            layer.AnchorPoint = new CoreGraphics.CGPoint(x: 0.5, y: 0.5);

            CATransform3D transform = CATransform3D.Identity;

            transform.m34 = 1 / -750;

            layer.SublayerTransform = transform;

            return layer;
        }

        CAAnimation RotationAnimation(RotationDirection direction)
        {
            CATransaction.Flush();

            var animationGroup = new CAAnimationGroup();

            animationGroup.Duration = 0.4;

            var rotation = new CABasicAnimation();
            var translationX = new CABasicAnimation();

            if (direction == RotationDirection.Right)
            {
                rotation = new CABasicAnimation() { KeyPath = "sublayerTransform.rotation.y" };

                //rotation.To   = NSNumber(float: radians(-90))//FIXME

                translationX = new CABasicAnimation() { KeyPath = "sublayerTransform.rotation.x" };

                    translationX.To = NSNumber(float: Float(TranslationForAnimation()));//FIXME
            }
            else if (direction == RotationDirection.Left)
            {
                rotation = new CABasicAnimation() { KeyPath = "sublayerTransform.rotation.y" };

                //rotation.To = NSNumber(float: radians(90))//FIXME

                translationX = new CABasicAnimation() { KeyPath = "sublayerTransform.rotation.x" };

                translationX.To = NSNumber(float: Float(TranslationForAnimation()));//FIXME
            }
            var translationZ = new CABasicAnimation() { KeyPath = "sublayerTransform.translation.z" };

            translationZ.To = NSNumber(float: Float(TranslationForAnimation()));//FIXME

            animationGroup.Animations = new CAAnimation[3] { rotation, translationX, translationZ };

            animationGroup.FillMode = kCAFillModeForwards; /// //FIXME TBD what is the constant? where is it?

            animationGroup.RemovedOnCompletion = false;

            animationGroup.Delegate = this; // or should this be = to aiimationGroup? 

            animationGroup.TimingFunction = CAMediaTimingFunction.FromName("kCAMediaTimingFunctionEaseInEaseOut");

            return animationGroup;
        }

        CALayer LayerFromView(UIView view)
        {
            var rect = new CGRect(0, 0, this.View.Bounds.Size.Width, this.View.Bounds.Size.Height);

            var imageLayer = new CALayer();

            imageLayer.AnchorPoint = new CGPoint(1, 1);

            imageLayer.Frame = rect;

            UIGraphics.BeginImageContextWithOptions(view.Frame.Size, false, UIScreen.MainScreen.Scale);

            // No idea how to convert "if..let..??" from swift.
            // 
            //if let context = UIGraphicsGetCurrentContext() {//FIXME
            //view.layer.renderInContext(context)
            //}
            UIImage image = new UIImage( = UIGraphics.GetImageFromCurrentImageContext();//FIXME

            UIGraphics.EndImageContext();

            imageLayer.Contents = image.CGImage;


            return imageLayer;
        }

        CALayer LayerFromView(UIView view, CATransform3D transform)
        {
            var layer = LayerFromView(view);
            layer.Transform = transform;
            return layer;
        }

        System.nfloat Radians(System.nfloat degrees)
        {
            return degrees * float(M_PI) / 180;  //FIXME
        }

        System.nfloat TranslationForAnimation()
        {
            return CubeSize() / 2;
        }

        System.nfloat CubeSize()
        {
            return UIScreen.MainScreen.Bounds.Width;
        }

        FCBlackBackgroundView BackgroundView(UIColor color)
        {
            var view = new FCBlackBackgroundView() { Frame = this.View.Frame };
            view.BackgroundColor = color;

            return view;
        }

    }
}


/*

public override func animationDidStop(anim: CAAnimation, finished flag: Bool)//FIXME no suitable overrride found
{
if let layers = self.view.layer.sublayers {
for layer in layers {
if layer.isKindOfClass(FCRotateLayer.classForCoder()) {
layer.removeFromSuperlayer()

}
}
}
for view in self.view.subviews {
if view.isKindOfClass(FCBlackBackgroundView.classForCoder()) {
view.removeFromSuperview()

}
}
}



* 
*/
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43712526

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档