Visibility Converters in Xamarin Android - 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..

Related

How to bind method on RadioGroup on checkChanged event with data-binding

I was searching over the internet for how to perform the new cool android data-binding over the RadioGroup and I didn't find a single blog post about it.
Its a simple scenario, based on the radio button selected, I want to attach a callback event using android data binding. I don't find any method on the xml part which allows me to define a callback.
Like here is my RadioGroup:
<RadioGroup
android:id="#+id/split_type_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:checkedButton="#+id/split_type_equal"
android:gravity="center"
<!-- which tag ? -->
android:orientation="horizontal">
...
</RadioGroup>
How do I attach a handler method which will be called on RadioGroup's checkChnged event will fire using data-binding?
I have tried using onClick (don't know if it is the same) in layout file and defining method in the Activity and located it using this in the layout file:
<variable
name="handler"
type="com.example.MainActivity"/>
...
<RadioGroup
android:onClick="handler.onCustomCheckChanged"
.. >
And defined method onCustomCheckChanged like this:
public void onCustomCheckChanged(RadioGroup radio, int id) {
// ...
}
But, it gives me the compilation error:
Error:(58, 36) Listener class android.view.View.OnClickListener with method onClick did not match signature of any method handler.onCustomCheckChanged
I have seen many blogs mentioning it is possible with RadioGroup but non of them really say how. How can I handle this with data-binding ?
After digging to the bunch of methods, I found this question on SO which helped me understand how to bind single methods of listeners.
Here is what to do with RadioGroup:
In RadioGroup listener you have a method onCheckedChanged(RadioGroup g, int id). So you can directly bound that method to your handler or your activity by passing an instance of it as a variable in layout file and calling a method with the same signature.
So call on layout file like this:
<RadioGroup
android:id="#+id/split_type_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:checkedButton="#+id/split_type_equal"
android:gravity="center"
android:onCheckedChanged="#{handler.onSplitTypeChanged}"
android:orientation="horizontal">
...
</RadioGroup>
And in my activity or handler, I need to simply provide the method with same name and signature like this:
public void onSplitTypeChanged(RadioGroup radioGroup,int id) {
// ...
}
Just make sure method is public.
NOTE: This works for any (most of, I have not tried all) listener methods. Like for EditText you can provide android:onTextChanged and so on.
I am using a string, and in this case I have bindable based on viewModel.getCommuteType() viewModel.setCommuteType(String)
<RadioGroup
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.DRIVING)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.DRIVING)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="D"/>
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.BICYCLE)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.BICYCLE)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"/>
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.WALKING)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.WALKING)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="W"/>
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.BUS)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.BUS)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="T"/>
After some hours I found easy way: two-way databinding in android. It's base skeleton with livedata and Kotlin. Also you can use ObservableField()
Set your viewmodel to data
Create your radiogroup with buttons as you like. Important: set all radio buttons id !!!
Set in your radio group two-way binding to checked variable (use viewmodel variable)
Enjoy)
layout.xml
<data>
<variable
name="VM"
type="...YourViewModel" />
</data>
<LinearLayout
android:id="#+id/settings_block_env"
...
>
<RadioGroup
android:id="#+id/env_radioGroup"
android:checkedButton="#={VM.radio_checked}">
<RadioButton
android:id="#+id/your_id1"/>
<RadioButton
android:id="#+id/your_id2" />
<RadioButton
android:id="#+id/your_id3"/>
<RadioButton
android:id="#+id/your_id4"/>
</RadioGroup>
</LinearLayout>
class YourViewModel(): ViewModel {
var radio_checked = MutableLiveData<Int>()
init{
radio_checked.postValue(R.id.your_id1)//def value
}
//other code
}
Often you care more about what was actually checked instead of "something was checked". In such case alternative solution is to ignore RadioGroup and bind all items as below:
<RadioGroup (...) >
<RadioButton (...)
android:checked="#={viewModel.optionA}"/>
<RadioButton (...)
android:checked="#={viewModel.optionB}"/>
<RadioButton (...)
android:checked="#={viewModel.optionC}"/>
</RadioGroup>
where optionA, optionB and optionC are defined in ViewModel like below:
public final ObservableBoolean optionA = new ObservableBoolean();
public final ObservableBoolean optionB = new ObservableBoolean();
public final ObservableBoolean optionC = new ObservableBoolean();
This is usually enough, however if you want to react immediately on click then you can add callBacks and use them like that:
OnPropertyChangedCallback userChoosedA = new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(Observable sender, int propertyId) {
(...) // basically propertyId can be ignored in such case
}
};
optionA.addOnPropertyChangedCallback(userChoosedA);
Advantage of such approach is that you don't need to compare and track "id".
In my current project, I did it like this.
I have three currency in the project and I choose one of them via RadioGroup.
It's enum with currencies:
enum class Currency(val value: Byte) {
USD(0),
EUR(1),
RUB(2);
companion object Create {
fun from(sourceValue: Byte): Currency = values().first { it.value == sourceValue }
fun from(sourceValue: String): Currency = values().first { it.toString() == sourceValue }
}
}
A piece of my ViewModel:
class BaseCurrencyViewModel : ViewModelBase<BaseCurrencyModelInterface>() {
/**
* Selected currency
*/
val currency: MutableLiveData<Currency> = MutableLiveData()
/**
*
*/
init {
currency.value = Currency.USD // Init value
}
}
Part of my layout (pay attention to binding in RadioGroup and tags of RadioButton):
<RadioGroup
android:id="#+id/currencySwitchers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:selectedCurrency = "#{viewModel.currency}"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintEnd_toEndOf="parent">
<RadioButton
android:id="#+id/usdSwitcher"
android:text="USD"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:tag="USD"
/>
<RadioButton
android:id="#+id/eurSwitcher"
android:text="EUR"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:tag="EUR"
/>
<RadioButton
android:id="#+id/rubSwitcher"
android:text="RUB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:tag="RUB"
/>
</RadioGroup>
And the final part - binding adapter.
#BindingAdapter("selectedCurrency")
fun setSelectedCurrency(view: View, value: MutableLiveData<Currency>?) {
view.getParentActivity()?.let { parentActivity ->
value?.observe(parentActivity, Observer { value ->
view.findViewWithTag<RadioButton>(value.toString())
?.also {
if(!it.isChecked) {
it.isChecked = true
}
}
}
)
(view as RadioGroup).setOnCheckedChangeListener { radioGroup, checkedId ->
val currency = Currency.from(radioGroup.findViewById<RadioButton>(checkedId).tag as String)
if(value != null && value.value != currency) {
value.value = currency
}
}
}
}
In this way, I got two-way binding between RadioGroup and a property in my ViewModel.

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}" />

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.

Bind button click inside customlayout using mvvmcross and mvxlistview

i wanted to bind a button click event inside my customlayout, below is my customlayout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="63dp">
<LinearLayout
android:orientation="horizontal"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:text="Accept"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/acceptBtnOnList"
android:background="#color/green_color"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"
android:layout_weight="1"
android:textColor="#android:color/background_light"
local:MvxBind="Click AcceptCommand" />
</LinearLayout>
</RelativeLayout>
below is my ListView layout
<?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"
android:background="#android:color/background_light">
<Mvx.MvxListView
android:id="#+id/ListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="#FFDAFF7F"
local:MvxBind="ItemsSource MyList; ItemClick ShowDetailCommand"
local:MvxItemTemplate="#layout/customlayout" />
</LinearLayout>
as you can see above i have called my customlayout inside the listview layout
Below is my ViewModelClass
public class ListViewModel : BaseViewModel
{
public IListService ListService { get; set; }
private MvxCommand _acceptCommand;
private ListAcceptedResult _accepted;
private MvxCommand _detailsCommand;
private ObservableCollection<MyCustomClass> _myList = new ObservableCollection<MyCustomClass>();
public ListViewModel(IListService listService)
{
ListService = listService;
}
public ObservableCollection<MyCustomClass> MyList
{
get { return _myList; }
set
{
_myList = value;
RaisePropertyChanged(() => MyList);
}
}
public ListAcceptedResult Accepted
{
get { return _accepted; }
set
{
_accepted = value;
RaisePropertyChanged(() => Accepted);
Update();
}
}
public ICommand AcceptCommand
{
get
{
IsLoading = true;
return
new MvxCommand<MyCustomClass>(
item =>
//On Success assigning the returned value from service to Accepted Property,
error => { IsLoading = false; ReportError(error.Message); }));
}
}
public async System.Threading.Tasks.Task Update()
{
//update logic
}
}
But i am not able to bind the AcceptCommand command to my button.
i am aware that this will not work because inside my customlayout view i do not get the AcceptCommand command as it is not a part of object MyCustomClass
please help me with some example.
Thanks in advance
As you know, data binding works by binding directly to the current ViewModel/Model. You're not able to access properties or commands of the parent view model, unless you provide a property to access the parent.
Anyway, one option is to create a value converter that you use in your binding. This converter will return a MvxCommand object that when executed will use MvxMessenger to publish a message.
The parent view model will subscribe to this message and then execute the command that you want.
I've created a sample based on Stuart Lodge's N=02 example.
https://github.com/kiliman/MvxCommandToMessage
EDIT: I modified the sample to use a generic MessageToCommandValueConverter. You can now pass in the message type in the binding. You still need specific message types though since MvxMessenger.Publish() is global to your app. See the code on GitHub for the changes.
Here's the value converter:
public class KittenAcceptedMessageValueConverter : MvxValueConverter<Kitten, ICommand>
{
protected override ICommand Convert(Kitten kitten, Type targetType, object parameter, CultureInfo culture)
{
return new MvxCommand(() =>
{
var messenger = Mvx.Resolve<IMvxMessenger>();
var message = new KittenAcceptedMessage(this, kitten);
messenger.Publish(message);
});
}
}
And here's how you bind to it in your layout. Use . to pass the current object to the converter.
<Mvx.MvxImageView
android:layout_width="75dp"
android:layout_height="75dp"
android:layout_margin="10dp"
local:MvxBind="ImageUrl ImageUrl; Click KittenAcceptedMessage(.)" />
And then finally in your ViewModel, you would subscribe to this message, and call your command:
_messenger.Subscribe<KittenAcceptedMessage>(message =>
{
KittenAcceptedCommand.Execute(message.Kitten);
});
private MvxCommand<Kitten> _kittenAcceptedCommand;
public ICommand KittenAcceptedCommand
{
get
{
_kittenAcceptedCommand = _kittenAcceptedCommand ?? new MvxCommand<Kitten>(kitten =>
{
var toast = Mvx.Resolve<IToastPlugin>();
toast.Show(string.Format("You accepted {0}", kitten.Name));
});
return _kittenAcceptedCommand;
}
}
Hope this helps.

Struggling to bind local images in an MvxImageView with MvvmCross

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"

Categories

Resources