Using View Binding in Widget android - android

I am using Widget for my Android application .
I need to know how can I apply view binding concept for RemoteViews in widget
Code :
// Construct the RemoteViews object.
val views = RemoteViews(context.packageName, R.layout.name_of_layout)
views.setTextViewText(R.id.textViewWidgetId, appWidgetId.toString())
views.setTextViewText(R.id.appwidget_update, context.resources.getString(R.string.date_count_format, count, dateString))

Related

Add views to activity at runtime using MVVM in Android

I have many activities in my application. Each activity has many UI elements like EditText, TextView, DatePicker, DropDown etc. Activity has both static components (views statically placed in xml layout) and dynamic components (views added at runtime based on business logic and API response). The UI elements to be added in activity are dynamic. What all UI elements needs to be added, depends on the API response.
I'm thinking about writing a method which takes in the information about what all views to be added as parameter and constructs the view and return it as a LinearLayout with all child views added.
In the code snippet below, rowBuilder is a data class which stores information about the views to be added at runtime. The method will build a vertical linearLayout with all the views needed and return it.
fun getUIFields(context: Context, rowBuilderList: ArrayList<RowBuilder>): LinearLayout {
val rootVerticalLinearLayout: LinearLayout = getRootVerticalLinearLayout(context)
for(i in 0 until rowBuilderList.size) {
val horizontalLinearLayout = getHorizontalLinearLayout(context)
for (j in 0 until rowBuilderList[i].columnBuilderList.size) {
val formFieldInfo = rowBuilderList[i].columnBuilderList[j].formFieldInfo
if (formFieldInfo.formFieldType == FormFieldType.EDIT_TEXT) {
addEditText(formFieldInfo, horizontalLinearLayout, context, i.toString() + j.toString())
} else if (formFieldInfo.formFieldType == FormFieldType.DATE_PICKER) {
addEditTextForDatePicker(formFieldInfo, horizontalLinearLayout, context, i.toString() + j.toString())
}
}
rootVerticalLinearLayout.addView(horizontalLinearLayout, i)
}
return rootVerticalLinearLayout
}
Where do I place the above logic, which requires context? I know we have AndroidViewModel, wherein I can use context. Also, If I write the above logic in ViewModel, the same code needs to be duplicated in every viewmodels. I need to know about a more efficient approach using MVVM
Please help!

setImageViewResource in Remote Views object pass an image using glide

I am making a Widget and in the Widget service in the getViewAt method i have set corrently the text to my widget but it is complicated to pass my images from my object.
#Override
public RemoteViews getViewAt(int position) {
RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
Automoviles autoService=mArraylistAutomoviles.get(position);
String imagen=autoService.getImagen();
String marca =autoService.getMarca();
// int imagenInt= Integer.parseInt(imagen);
// Update the plant image
views.setImageViewResource(R.id.widget_image_item, R.drawable.mazda2azul);
views.setTextViewText(R.id.textView,marca);
return views;
}
Notice that in order to retreive the images i need to use Glide(Thats what i use in my project) .At the moment i have R.drawable.mazda2azul that is an int so the method doesnt complain .String imagen=autoService.getImagen return the following Url = https://firebasestorage.googleapis.com/v0/b/udacitycapstonefinal.appspot.com/o/CarImages%2Fford_escape_negra.jpeg?alt=media&token=89ea95d3-852c-4d24-9f09-b9ef519928a3
I tried to do
int imagenInt= Integer.parseInt(imagen);
but it didnt load the widget images or Text .
So i need a way to do the Glide part and pass it to the
setImageResource second parameter. This is my big problem.
You can use this method:
Bitmap bitmap = Glide.
with(context).
load(imagen).
asBitmap().get();
views.setImageViewBitmap(R.id.widget_image_item, bitmap);

Is it possible to create 2 FirebaseListOptions<> options based on the value returned from the model class?

I am trying to populate the chat messages using FirebaseListAdapter.
Below is the code.
FirebaseListOptions<UserChat> options = new FirebaseListOptions.Builder<UserChat>()
.setQuery(queryforDisplayMessages, UserChat.class)
.setLayout(R.layout.chat_user2_item)
.setLifecycleOwner(this)
.build();
final FirebaseListAdapter<UserChat> adapter=new FirebaseListAdapter<UserChat>(
options
) {
#Override
protected void populateView(View v, UserChat model, int position) {
Log.d(TAG,"Inside populateView");
TextView tv=(TextView)v.findViewById(R.id.textview_message);
tv.setText(model.getMessage());
}
};
listView.setAdapter(adapter);
I have to differentiate the chat sent and chat received. So in the FirebaseListOptions options I have to use 2 different layouts based on if its a chat sent or chat received. I have a value,called UserModel, in UserChat model class ,from which I can differentiate if its a chat sent or received. But how to use it in the above code and create 2 different FirebaseListOptions ?
No, but I'm guessing you're looking for a way to display different views based on the model. This is possible through view types: https://stackoverflow.com/a/26245463/4548500
change from listoptions to recycler options this will allow you to create your custom layout everytime using recycler view has more options than list view

Android AppWidget Listview change selected imagebutton onClick

I've this homescreen widget:
It's easy to update for example two buttons next to the logo from activity, because I have their appWidgetIds from onUpdate method from AppWidgetProvider, but imagebuttons in the list are created in RemoteViewsFactory class in getViewAt() method.
#Override
public RemoteViews getViewAt(int position) {
RemoteViews row = new RemoteViews(ctxt.getPackageName(), R.layout.list_row_widget);
row.setTextViewText(R.id.tvDescription, items.get(position).name);
Intent i = new Intent();
Bundle extras = new Bundle();
extras.putBoolean(TimeWidgetProvider.ACTION_WORK_START, true);
extras.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
i.putExtras(extras);
row.setOnClickFillInIntent(R.id.btnStartWork, i);
return (row);
}
so every of them have same id (R.id.btnStartWork), and same appWidgetId which is not the row id but the whole widget id.
I need to change imagebutton in the row which I have clicked on, but because I've only one appwidget id in Activity and its for whole widget, everytime I use:
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getBaseContext());
RemoteViews views = new RemoteViews(getBaseContext().getPackageName(), R.layout.widget_layout);
views.setImageViewResource(R.id.btnStartWork, R.drawable.button_active);
appWidgetManager.updateAppWidget(mAppWidgetId, views);
It changes the first imagebutton not the selected one.
I have tried to pass remoteviews row from factory, but it didn't work because when I called
appWidgetManager.updateAppWidget(mAppWidgetId, row);
with the id of whole widget, widget was gone and only the selected row was visible. I can get the position of item in list, but it's not helpful because it's not a viewId.
I have read many tutorial including this: http://developer.android.com/guide/topics/appwidgets/index.html
But still haven't found the answer, It's my first widget. Help please.
Thanks ;)
Actually the solution was quite simple, in getViewAt() method save the position of every imagebutton to extras:
extras.putInt(TimeWidgetProvider.POSITION, position);
then in handling method store somewhere the index of selected item
TimeWidgetProvider.selected = extras.getInt(TimeWidgetProvider.POSITION);
and after that, use this:
appWidgetManager.notifyAppWidgetViewDataChanged(mAppWidgetId, R.id.list);
at last again in the getViewAt() method change imagebutton on index which you have previously stored.
if (position == TimeWidgetProvider.selected) {
row.setImageViewResource(R.id.btnStartWork, R.drawable.button_active);
} else {
row.setImageViewResource(R.id.btnStartWork, R.drawable.button_inactive);
}
The whole list is refreshed with changed states of selected items.
Thx Tamás Müller for this solution.

Bind RadioGroup inside MvxListView

I've got some very tricky problem. I already tried to search the web and even looked into the MvvmCross sources, but I don't seem to be able to figure it out.
I have an MvxListView with a custom Adapter. The reason is, that depending on the "DataContext" of the current ListItem, I want to display some different view.
The list itself represents some sort of questionnaire. So the items in the list are in the form of
new Question("do you need help?"){
new Answer("yes"),
new Answer("no"),
new Answer("maybe")
}
Now the answers shall be shown as a radio button list.
So in my custom adapter on "GetChildView", I retrieve the view with the radiogroup and then I
"just want to bind that group to my answers" --> so for each answer, there has to be a corresponding radiobutton.
I would love to have the "Answer" object as datacontext for each radiobutton.
radioButton.Bind("Checked", "Chosen"); // where "Chosen" is the boolean property on "Answer"
But it would already be fine if the "Question" object could be the datacontext that I bind to
radioGroup.Bind("CheckedRadioButtonId", "ChosenAnswer"); // where "ChosenAnswer" is an int property
on "Question"
So basically I want to bind my radiobutton to the MvxListItem.DataContext in code inside my customadapter.
But I just cannot figure out how to do that. :/
Can you please give me a hint?
Of course I would love to do the same with a list of checkboxes as soon as multiple answers would be allowed.
Setting the datacontext is easy: just set it :)
What you do is you create a ViewModel called something like QuestionViewModel, which has what you need as a separet ViewModel.
Then create some component to use in your View for the complete questionnaire. Below is some example code for a bindable component.
public class BindableLinearLayout : ClickableLinearLayout, IMvxDataConsumer, IMvxBindingContextOwner
{
public BindableLinearLayout(Orientation orientation, object dataContext)
: base(orientation)
{
BindingContext = new MvxBindingContext();
DataContext = dataContext;
}
public object DataContext { get { return BindingContext.DataContext; }
set { BindingContext.DataContext = value; }
}
public IMvxBindingContext BindingContext { get; set; }
}
In the Questionnaire View, create this component and assign the datacontext (in the above example as a parameter). Then you can create the binding in the normal way:
var bindings2 = layout.CreateBindingSet<BindableLinearLayout, ParagraphViewModel>();
bindings2.Bind(numberText.View).For(t => t.Text).To(vm => vm.Paragraph.Number);
bindings2.Apply();
This code is called for each element you add to the collection, eauch with its own Datacontext.
I known this code is not for a list adapter, but I hope this will give you enough hints how to do this yourself.

Categories

Resources