Consume native android library in Xamarin Forms that is UI element

LeoJHarrisLeoJHarris NZMember ✭✭✭

I'm attempting to create and consumable native android library for in my Xamarin.Forms project, native lib is here: https://github.com/florent37/DiagonalLayout

I've created the binding library project with the exported .aar and built the project with no errors.

I've also created an Xamarin Forms library project which references the android binding library so wrap the native component. See below:

The problem I am facing is when I run the application I get this error:

System.InvalidCastException: Specified cast is not valid.

The base UI element in the native project derives from android.widget.framelayout and I am trying to use as a frame in my forms project which i cant, but its the only way I really see how:

public class XFDiagonalView : Frame { }

I would really appreciate any help to resolve this issue and to be able to wrap the Android binding library for my XF project.

Best Answer

Answers

  • JarvanJarvan Member, Xamarin Team Xamurai
  • LeoJHarrisLeoJHarris NZMember ✭✭✭
    edited April 2019

    @yelinzh Thanks for the response! :smile: I had tried that ViewRenderer earlier but wasn't quite sure how that worked but its working now.

    I can now see the diagonal view showing a little wohoo! However the the diagonal view is not cutting/cropping the image off at the dividing line :neutral:

    On the Github native android project usage is:

    <com.github.florent37.diagonallayout.DiagonalLayout
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:elevation="10dp"
            app:diagonal_angle="20"
            app:diagonal_position="top"
            app:diagonal_direction="right">
    
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/mountains" />
    
    </com.github.florent37.diagonallayout.DiagonalLayout>
    

    So, my xaml looks as follows:

    <RelativeLayout>
            <xfdiagonallayout:XFDiagonalView>
                <Image Source="https://img-aws.ehowcdn.com/877x500p/s3-us-west-1.amazonaws.com/contentlab.studiod/getty/f24b4a7bf9f24d1ba5f899339e6949f3" />
            </xfdiagonallayout:XFDiagonalView>
        </RelativeLayout>
    

    Then in my renderer I initialize a new instance of the native DiagonalLayout:

      public class DiagonalViewRenderer : ViewRenderer<XFDiagonalView, DiagonalLayout>
        {
            Context _context;
    
            public DiagonalViewRenderer(Context context) : base(context)
            {
                _context = context;
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<XFDiagonalView> e)
            {
                base.OnElementChanged(e);
    
                if (e.NewElement is XFDiagonalView xFDiagonalView)
                {
                    Image img = xFDiagonalView.Content as Image;
                    IVisualElementRenderer vRenderer = Platform.CreateRendererWithContext(img, _context);
                    Android.Views.View viewGroup = vRenderer.View;
    
                    if (viewGroup is ImageRenderer imageRenderer)
                    {
                        ImageView imageView = new ImageView(_context);
                        imageView.SetScaleType(ScaleType.CenterCrop);
    
            // Assign new image to the native image view, we needed to set CenterCrop on native ImageView
                        Bitmap myBitmap = BitmapFactory.DecodeFile(img.Source.ToString());
                        imageView.SetImageBitmap(myBitmap);
    
            // Create DiagonalLayout and apply same properties and values as native lib had
                        DiagonalLayout diagonalLayout= new DiagonalLayout(_context)
                        {
                            Elevation = 10,
                            DiagonalAngle = 20,
                            DiagonalPosition = DiagonalLayout.DirectionLeft,
                            DiagonalDirection = DiagonalLayout.DirectionRight,
                            LayoutParameters = new ViewGroup.LayoutParams(300, 300)
                        };
    
            // Add the native imageView to diagonalLayout
                        diagonalLayout.AddView(imageView, 0);
                        SetNativeControl(diagonalLayout);
                    }
                }
            }
        }
    

    One thing that did occur to me is that if I have multiple views in the xaml file

    <xfdiagonallayout:XFDiagonalView>
    ....
    </xfdiagonallayout:XFDiagonalView>
    

    Then I'd need to re-add them to the diagonalLayout before calling SetNativeControl(diagonalLayout), because essentially the SetNativeControl method replace the original view in XF with the native view?

    I have create a project for the source code here: https://github.com/LeoJHarris/XFDiagonalLayout

    Hoping to make a nuget package out of it for Xamarin forms.

  • JohnHJohnH GBMember ✭✭✭✭✭
    edited April 2019

    PMFJI, Im not sure why you need an Android library for this? From what I have seen of the requirements it can all be done in Xamarin.Forms and would work in iOS and Droid and any other XF supported OS.

    I see the page broken down into stack layouts, grids, an image, and slightly rotated box view. If the image needs to animate across, use a larger image and show it larger than the screen and animate the TranslateX.
    The box in the first row of the grid would also be larger and slightly rotated. A bit of trial and error to get the layout right and this could be done in a few hours.

  • LeoJHarrisLeoJHarris NZMember ✭✭✭

    @JohnHair I was opting for the native library method because the app is android only and and what seemed like a simple library existed in native android I could create a quick binding for it, it was exactly as I wanted it. I figured it would be a good learning example as well to get this to work, but it seems more worry then its worth so will prob opt to create it through Xamarin Forms then

  • LeoJHarrisLeoJHarris NZMember ✭✭✭
    Accepted Answer

    Solved this in Xamarin Forms using absolute layout (but I don't doubt it could also be achieved as you mentioned @JohnHair )

    See answer here:

    https://forums.xamarin.com/discussion/comment/369665#Comment_369665

Sign In or Register to comment.