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
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);
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.
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}" />
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..
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.