Bismarck
Bismarck

Reputation: 115

Convert Android Custom ImageView to Xamarin.Android

I am trying to create a custom ImageView class by extending the Android core ImageView class using Xamarin.Android. Below is a piece of the code in Java and an incomplete implementation in C#. I need help with the last 2 methods.

ANDROID JAVA CODE

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.ImageView;

public class IconViewView extends ImageView {

private ColorStateList tint;

public IconView(Context context) {
  super(context);
}

public IconView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init(context, attrs, 0);
}

public IconView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  init(context, attrs, defStyle);
}

private void init(Context context, AttributeSet attrs, int defStyle) {
  TypedArray a = context.obtainStyledAttributes(
  attrs, R.styleable.IconView, defStyle, 0);
  tint = a.getColorStateList(R.styleable.IconView_iconTint);
  a.recycle();
}

@Override
protected void drawableStateChanged() {
  super.drawableStateChanged();
  if (tint != null && tint.isStateful()) {
    updateTintColor();
  }
}

public void setColorFilter(ColorStateList tint) {
  this.tint = tint;
  super.setColorFilter(tint.getColorForState(getDrawableState(), 0));
}

private void updateTintColor() {
  int color = tint.getColorForState(getDrawableState(), 0);
  setColorFilter(color);
}

} 

ANDROID XAMARIN C# CODE

using Android.Content;
using Android.Content.Res;
using Android.Graphics;
using Android.Support.V4.Content;
using Android.Support.V4.Graphics.Drawable;
using Android.Util;
using Android.Widget;

namespace Example.Droid.App.Views
{
    public class IconView : ImageView
    {
        private ColorStateList tint;
        private Context context;
        public IconView(Context context) :base(context)
    {
        Initialize(context, null, 0);
    }

    public IconView(Context context, IAttributeSet attrs) :
        base(context, attrs)
    {
        Initialize(context, attrs, 0);
    }

    public IconView(Context context, IAttributeSet attrs, int defStyle) :
        base(context, attrs, defStyle)
    {
        Initialize(context, attrs, defStyle);
    }

    void Initialize(Context mContext, IAttributeSet attrs, int defStyle)
    {
        context = mContext;
        TypedArray a = context.ObtainStyledAttributes(attrs, Resource.Styleable.IconView, defStyle, 0);
        tint = a.GetColorStateList(Resource.Styleable.IconView_iconTint);
        a.Recycle();
    }

    protected override void DrawableStateChanged()
    {
        base.DrawableStateChanged();
        if (tint != null && tint.IsStateful)
            UpdateTintColor();
    }

    private void UpdateTintColor() {
        /* I NEED HELP HERE */
    }
    public void SetColorFilter(ColorStateList tint) {
        /* I NEED HELP HERE */
    }

   }
}

I need some help with these methods in Xamarin C#

private void UpdateTintColor() {
    /* I NEED HELP HERE */
}
public void SetColorFilter(ColorStateList tint) {
    /* I NEED HELP HERE */
}

Upvotes: 0

Views: 607

Answers (2)

Bismarck
Bismarck

Reputation: 115

Finally I got it working. I extended the AppCompatImageView instead and thanks to Jon Douglas. Here is my code

1. App/View/IconView.cs

using System;
using Android.Content;
using Android.Content.Res;
using Android.Graphics;
using Android.Support.V4.Content;
using Android.Support.V4.Graphics.Drawable;
using Android.Support.V7.Widget;
using Android.Util;
using Android.Widget;

namespace Example.Droid.App.Views
{
    public class IconView : AppCompatImageView
    {
        private ColorStateList tint;
        private Context context;
        public IconView(Context context) :base(context)
    {
        Initialize(context, null, 0);
    }

    public IconView(Context context, IAttributeSet attrs) :
        base(context, attrs)
    {
        Initialize(context, attrs, 0);
    }

    public IconView(Context context, IAttributeSet attrs, int defStyle) :
        base(context, attrs, defStyle)
    {
        Initialize(context, attrs, defStyle);
    }

    void Initialize(Context mContext, IAttributeSet attrs, int defStyle)
    {
        context = mContext;
        TypedArray a = context.ObtainStyledAttributes(attrs, Resource.Styleable.IconView, defStyle, 0);
        tint = a.GetColorStateList(Resource.Styleable.IconView_iconTint);
        a.Recycle();
    }

    protected override void DrawableStateChanged()
    {
        base.DrawableStateChanged();
        if (tint != null && tint.IsStateful)
            UpdateTintColor();
    }

   private void UpdateTintColor()
    {
        var color = new Color(tint.GetColorForState(GetDrawableState(), new Color(0)));
        SetColorFilter(color);
    }

    public void SetColorFilter(ColorStateList tint)
    {
        this.tint = tint;
        base.SetColorFilter(new Color(tint.GetColorForState(GetDrawableState(), new Color(0))));
    }

   }
}

2. Part of Resources/layout/activity_example.axml

<Example.Droid.App.Views.IconView
 android:layout_width="30dp"
 android:layout_height="30dp"
 app:srcCompat="@drawable/ic_camera"
 android:layout_margin="5dp"
 android:duplicateParentState="true"
 app:iconTint="@color/primary_selector"/>

3. Resources/color/primary_selector.xml

<?xml version="1.0" encoding="utf-8"?>
  <selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_pressed="true"
      android:color="#FFFFFF"/> <!-- pressed -->
  <item android:state_selected="true"
      android:state_focused="true"
      android:color="#FFFFFF"/> <!-- focused -->
  <item android:color="#CCCCCC"/> <!-- default -->
</selector>

4. Resources/values/attrs.xml

<?xml version="1.0" encoding="UTF-8" ?>
  <resources>
   <declare-styleable name="IconView">
    <attr name="iconTint" format="reference|color" />
   </declare-styleable>
  </resources>

5. Resources/drawable/ic_camera.xml

<?xml version="1.0" encoding="UTF-8" ?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M4,4H7L9,2H15L17,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4M12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17A5,5 0 0,0 17,12A5,5 0 0,0 12,7M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9Z" />

Cheers...

Upvotes: 0

Jon Douglas
Jon Douglas

Reputation: 13176

Use new Color() and it's overloads whenever you need to convert an int to a Color.

https://developer.xamarin.com/api/constructor/Android.Graphics.Color.Color/p/System.Int32/

private void UpdateTintColor()
{
    var color = new Color(tint.GetColorForState(GetDrawableState(), new Color(0)));
    SetColorFilter(color);
}
public void SetColorFilter(ColorStateList tint)
{
    this.tint = tint;
    base.SetColorFilter(new Color(tint.GetColorForState(GetDrawableState(), new Color(0))));
}

There are multiple outstanding bugs on this issue here:

https://bugzilla.xamarin.com/show_bug.cgi?id=36396#c3 https://bugzilla.xamarin.com/show_bug.cgi?id=57521

Please CC yourself on this issue and add a comment to describe the difficulty using this API without the extension methods and we'll work on improving these.

Upvotes: 2

Related Questions