Struggling to bind local images in an MvxImageView with MvvmCross - android

I can't seem to get images to bind properly in an MvxListView
Here is the template:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Mvx.MvxImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="10dp"
local:MvxBind="ImageUrl IconName, Converter=IconSource" />
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="30dp"
local:MvxBind="Text Name" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20dp"
local:MvxBind="Text Description" />
</LinearLayout>
</LinearLayout>
Here is the converter:
public class IconSourceValueConverter : MvxValueConverter<string, string>
{
protected override string Convert(string value, Type targetType, object parameter, CultureInfo culture)
{
//string retval = string.Format("res:{0}", value.ToLower());
string retval = string.Format("#drawable/{0}", value.ToLower());
return retval;
}
}
All the images are present in the Drawable folder.
I tried both drawable and res and neither work.
I replaced the MvxImageView with a plain ImageView containing a hard coded android:src and it worked fine.
Any ideas?

I have used this to make it work for me:
public class StringToIntValueConverter : MvxValueConverter<string, int>
{
protected override int Convert(string value, Type targetType, object parameter, CultureInfo culture)
{
int image = 0;
if(value == "song")
image = Resource.Drawable.icon_category_song;
return image;
}
}
To use this in the Android layout:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
local:MvxBind="DrawableId StringToInt(Type)" />
In this example "Type" is a string containing the word "song".

Thanks ,it's working.Tried with MVXImageview
public class PercentToImageConverter : MvxValueConverter<int, int>
{
protected override int Convert(int value, Type targetType, object parameter, CultureInfo culture)
{
switch (value)
{
case 10:
return Resource.Drawable.Percent10;
case 40:
return Resource.Drawable.Percent40;
case 60:
return Resource.Drawable.Percent60;
case 80:
return Resource.Drawable.Percent80;
case 100:
return Resource.Drawable.Percent100;
default:
return Resource.Drawable.Percent0;
}
}
}
Android Layout
<Mvx.MvxImageView
android:layout_width="25dp"
android:layout_gravity="center"
android:layout_height="25dp"
local:MvxBind="DrawableId PercentToImage(Percent)" />

In xml use: local:MvxBind="ImageUrl IconName"
In ViewModel: IconName="res:image_name"
eg.In drawable resource image name like "image_name.png"

Related

two way binding with null check

In data binding adatper, i want to check if int value in my model is not zero. Because hint is never shown, if value is 0 default then 0 is shown as text. I want to show hint if value is zero.
Below works well without checking 0 int value
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/port"
android:inputType="number"
android:text="#={`` + item.port}"
/>
I tried this which does not work
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/port"
android:inputType="number"
android:text='#={item.port != 0 ? `` + item.port : ""}'
/>
item.port is intvalue
Any suggestions to make this work with only data binding?
I think you'll need a BindingAdapter/InverseBindingAdapter or a conversion method. The easiest is probably a conversion method:
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<data>
<import type="com.example.mount.teststuff.Conversion"/>
<variable name="port" type="int"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="#+id/input"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#={Conversion.intToString(port, port)}"
android:textSize="40sp"/>
<TextView
android:id="#+id/output"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{`` + port}"
android:textSize="40sp"/>
</LinearLayout>
</layout>
And in your Conversion class you'd have something like this:
public class Conversion {
#InverseMethod("stringToInt")
public static String intToString(int oldValue, int value) {
if (value == 0) {
return null;
}
return String.valueOf(value);
}
public static int stringToInt(int oldValue, String value) {
if (value == null || value.isEmpty()) {
return 0;
}
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return oldValue;
}
}
}
I just updated the answer to include my tested layout and code. You can look for more detail on this blog post.
<import type="Integer"/>
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/port"
android:inputType="number"
android:text='#={item.port}'
/>
Dont keep port variable as int as two way binding required String type Setter for port value. Instead convert String value into Integer in XML itself.
Update : Instead of checking null for hint, please change port value from your viewmodel. if port is 0 then you can replace it with empty string "" and then call notifyPropertyChange(BR.port);

ColorStateList Converter only works in debug mode

I have a converter that only works in debug mode. When I generate a Release .apk, it doesn't work anymore.
Here is my code:
public class CardapioImageColorConverter : MvxValueConverter<bool, ColorStateList>
{
private static Activity Activity => Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity;
protected override ColorStateList Convert(bool value, Type targetType, object parameter, CultureInfo culture)
{
ColorStateList color;
if (value)
color = Activity.Resources.GetColorStateList(Resource.Color.cor1,Activity.Theme);
else
color = Activity.Resources.GetColorStateList(Resource.Color.white, Activity.Theme);
return color;
}
}
And my axml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="70dp"
android:layout_height="70dp">
<Mvx.MvxImageView
android:id="#+id/imageView"
android:layout_weight="1"
android:tint="#color/white"
android:layout_width="match_parent"
android:layout_height="match_parent"
local:MvxBind="ImageUrl Icone;ImageTintList CardapioImageColor(Selecionado);"
android:layout_gravity="center" />
<TextView
local:MvxBind="Text Nome; TextColor CardapioTextColor(Selecionado);"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#color/cor1"
android:textSize="11dp"
android:layout_weight="1.9"
android:text="#string/lista_espera"
android:gravity="center"
android:layout_marginBottom="#dimen/margin_tiny"
android:layout_marginTop="#dimen/margin_tiny" />
</LinearLayout>
It works perfectly in debug mode. Do you have any idea why it happens?
I just found the solution!
I'm using linking, so, the converter wasn't working because the linker was enable.
I put this method in a class called "LinkerPleaseInclude".
public void Include(MvxImageView mvxImage)
{
mvxImage.ImageTintList = mvxImage.ImageTintList;
}
This class is never actually executed, but when Xamarin linking is enabled it does how to ensure types and properties are preserved in the deployed app.

How to make bold text with Android Data Binding Library

Pretty basic, I want to make a title of a message bold based on whether the text it is read or not. I can't seem to find a solution for this.
Here is my XML code:
<TextView
android:text="#{message.title}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:layout_toLeftOf="#+id/timestamp"
android:textSize="18sp"
android:textStyle='#{message.isRead() ? "bold" : "normal"}'
android:textColor='#{message.isRead() ? 0xff313131 : 0xff0662ab}' />
Th colorchange is working great, only the bold text is giving me some problems.
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
java.lang.RuntimeException: Found data binding errors.
****/ data binding error ****msg:Cannot find the setter for attribute 'android:textStyle' with parameter type java.lang.String on android.widget.TextView.
file:D:......xml
loc:39:41 - 39:79
****\ data binding error ****
An easy way
public class TextViewBindingAdapter {
#BindingAdapter("isBold")
public static void setBold(TextView view, boolean isBold) {
if (isBold) {
view.setTypeface(null, Typeface.BOLD);
} else {
view.setTypeface(null, Typeface.NORMAL);
}
}
}
XML:
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isBold="#{item.bold}"/>
I ended up using the following code, it implements DataBinding.
public abstract class BindingAdapter {
#android.databinding.BindingAdapter("android:typeface")
public static void setTypeface(TextView v, String style) {
switch (style) {
case "bold":
v.setTypeface(null, Typeface.BOLD);
break;
default:
v.setTypeface(null, Typeface.NORMAL);
break;
}
}
}
And the XML
<TextView
android:text="#{bericht.titel}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:layout_toLeftOf="#+id/timestamp"
android:textSize="18sp"
android:textColor='#{bericht.isGelezen() ? 0xff313131 : 0xff0662ab}'
android:typeface='#{bericht.isGelezen() ? "normal" : "bold"}' />
You can do this without creating an adapter.
Import Typeface to your XML
<data>
<import type="android.graphics.Typeface" />
...
</data>
Use the attribute android:typeface with Typeface.defaultFromStyle:
android:typeface="#{Typeface.defaultFromStyle(message.isRead() ? Typeface.BOLD : Typeface.NORMAL)}"
Saif Bechan is correct in his answer, I made a slight change to facilitate databinding from a view model.
public abstract class BindingAdapter {
#android.databinding.BindingAdapter("app:textStyle")
public static void setTextStyle(TextView v, int style) {
v.setTypeface(null, style);
}
}
Then you bring in the app namespace to your XML
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
...
</layout>
Create a binding in the view model
#Bindable
public int getValueFormat() {
String message = getMyObject().getValue();
if (message == MyObject.DEFAULT_VALUE)
return Typeface.ITALIC;
return Typeface.NORMAL;
}
Now you can bind this directly
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:textStyle="#{viewModel.valueFormat}"
android:text="#{viewModel.value}" />
you just has to import Typeface to the xml file and make your check like this
<variable
name="vm"
type="com.example.VM" />
<import type="android.graphics.Typeface" />
<TextView
android:id="#+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="#{vm.isBold ? Typeface.BOLD : Typeface.NORMAL}"/>
So, I had the same problem this week, I was trying to use the view.setTypeface() method, but I wanted to keep the font style in my case. It turns out that the bold style worked when I passed null in the setTypeFace method, but...passing null can make changes in the font style (was not looking at the same). When I tried to use the same font style and set the view to bold it was not working.
To achieve what I wanted, since I was not succeeding in using this method I just change the font style when the bold is required, see my code:
#BindingAdapter("boldOrRegular")
#JvmStatic
fun TextView.boldOrRegular(isBold: Boolean) {
typeface = if (isBold) {
ResourcesCompat.getFont(context, R.font.myfont_bold)
} else {
ResourcesCompat.getFont(context, R.font.myfont_regular)
}
}
I hope that this can help someone :)
You need to create getMessageStyle into your message Object :
public String getMessageStyle() {
return isRead() ? "bold" : "normal";
}
then use as below into your code :
<TextView
android:text="#{message.title}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:layout_toLeftOf="#+id/timestamp"
android:textSize="18sp"
android:textStyle="#{message.getMessageStyle()}"
android:textColor="#{message.isRead() ? 0xff313131 : 0xff0662ab}" />

Visibility Converters in Xamarin Android

I am creating a android application using MvvmCross, in which I have to show and hide some controls in listview depending upon the value. For that I have created a visibility converter in PCL like this
public class VisibilityValueConverter : MvxValueConverter<bool, MvxVisibility>
{
protected override MvxVisibility Convert(bool value, Type targetType, object parameter, CultureInfo culture)
{
return (value == true) ? MvxVisibility.Visible : MvxVisibility.Collapsed;
}
}
and I am using this value converter in my layout page like this
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20dp"
local:MvxBind="Text QuestionText"
android:layout_marginTop="15dp" />
<RadioGroup
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/radioGroup1"
android:layout_marginTop="5dp">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/radioButton1"
local:MvxBind="Text OptionA" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
local:MvxBind="Text OptionB"
android:id="#+id/radioButton2" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
local:MvxBind="Text OptionC"
android:id="#+id/radioButton3" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
local:MvxBind="Text OptionD"
android:id="#+id/radioButton4" />
</RadioGroup>
<EditText
android:layout_width="fill_parent"
android:layout_height="159.0dp"
android:textSize="20dp"
android:layout_marginTop="2dp"
local:MvxBind="Visibility TexboxVisible,Converter=Visibility" />
</LinearLayout>
But it's not working. It's not hitting the breakpoints in PCL value converter.
I have also tried to use MvxVisibility plugin but it's also not working.
I think I am doing something wrong. Can someone help and let me know how to use visibilty converters inside listview in android.
ViewModel
public class Question
{
public string Type { get; set; }
public bool RadioVisible { get; set; }
public bool TexboxVisible { get; set; }
}
private List<Question> _questionList;
public List<Question> QuestionList
{
get { return _questionList; }
set
{
_questionList = value;
RaisePropertyChanged(() => QuestionList);
}
}
private async void ShowQuestionsList(int assignmentId)
{
QuestionList = await _service.GetQuestionListByAssignmentAsync(assignmentId);
if (QuestionList != null)
{
foreach (Question q in QuestionList)
{
if (q.Type != null)
{
if (q.Type == "S")
{
q.RadioVisible = false;
q.TexboxVisible = true;
}
else if (q.Type == "O")
{
q.RadioVisible = true;
q.TexboxVisible = false;
}
}
}
}
}
My breakpoint in my Testconverter is fired as it should. My code:
public class TestMethodValueConverter : MvxValueConverter<bool, MvxVisibility>
{
protected override MvxVisibility Convert(bool value, Type targetType, object parameter, CultureInfo culture)
{
return value ? MvxVisibility.Visible : MvxVisibility.Collapsed;
}
}
And the View-Xaml:
local:MvxBind="Visibility MyBoolProperty, Converter=TestMethod"
But there is another problem. The android view elements can't change the visibility with the MvxVisibility enum. They need a Android.Vioews.ViewStates value.
So you need to add the converter in the Android project. Thats why we use the MvxVisibility-Plugin.
Edit
Your viewmodels should all inherit from MvxViewModel and the properties, which are used for binding need to implement the property-changed call RaisePropertyChanged(() => Property);. Otherwise nobody knows about changes. Thats the first point.
But the Converter should work at the first time without that (as far as I know). So I don't see anything other which can go wrong.. so try to create a simple clean project only with that problem and one single View-Element to reproduce what can go wrong..

Custom Visibility Converter - Android - Release (MvvmCross)

I've developed an application for Android using MvvmCross. There is a part of it in which it should show either a ImageView or a MvxImageView. When i test it in debug mode it works fine, but when i change it to release mode the visibility converter seem to stop working. All the other converters work they way the should, only those converters stop working.
A resume from my xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:scaleType="fitCenter"
local:MvxBind="Visibility MyObject, Converter=ByteInverseVisibility; AssetImagePath MyObject, Converter=AttachmentTypeToSource" />
<Mvx.MvxImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:maxHeight="150dp"
android:adjustViewBounds="true"
local:MvxBind="Visibility MyObject, Converter=ByteVisibility; Bitmap MyObject.Attachment, Converter=InMemoryImage" />
</LinearLayout>
The Converters:
public class ByteVisibilityConverter : MvxBaseVisibilityValueConverter<MyObjectClass>
{
protected override MvxVisibility Convert(MyObjectClass value, object parameter, CultureInfo culture)
{
if (value.AttachType == AttachmentType.Photo && value.Attachment != null)
{
return MvxVisibility.Visible;
}
return MvxVisibility.Collapsed;
}
}
public class ByteInverseVisibilityConverter : MvxBaseVisibilityValueConverter<MyObjectClass>
{
protected override MvxVisibility Convert(MyObjectClassvalue, object parameter, CultureInfo culture)
{
if (value.AttachType != AttachmentType.Photo || value.Attachment == null)
{
return MvxVisibility.Visible;
}
return MvxVisibility.Collapsed;
}
}
The reason is because that the Visibility property is not being included in the packaging.
You gotta add something like:
public void Include(ImageView imageView)
{
imageView.Visibility = imageView.imageView;
}
In your LinkerPleaseInclude.cs file.

Categories

Resources