i'm a beginner with xamarin android mvvmcross
i have an app who works fine with two activity
in the first activity i have a button when i click on the button i have this
<Button
android:layout_height="50dp"
android:layout_weight=".35"
android:layout_width="0dp"
android:background="#drawable/button_Green"
style="#style/button_text_white"
local:MvxBind="Click StartCommand" />
this button launch a second activity
on the second activity i have a edit text and a button
i would like on click on the button add text to the edit text ..but i don't know how to do this ...
is not really clear in my head sorry ...
thanks for your time
First declare a EditText in your layout:
<EditText
android:layout_height="wrap_content"
android:layout_width="fill_parent"
local:MvxBind="Text MyText">
</EditText>
Notice the Binding of the Text-property to "MyText". You need to add a public property with this name in your ViewModel:
class SecondViewModel: MvxViewModel
{
private string m_MyText;
public string MyText
{
get { return m_MyText; }
set
{
m_MyText = value;
RaisePropertyChanged();
}
}
// ...
}
As soon as you set the property MyText from within your ViewModel it will update the layout accordingly. It is required to call RaisePropertyChange in the setter of the property to tell the layout that there are changes.
Related
My normal edittext which works:
<EditText
android:id="#+id/emailEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/dimen_8_dp"
android:hint="Email"
android:imeOptions="actionNext"
android:inputType="textEmailAddress"
android:text="#={viewModel.emailId}"
android:textSize="#dimen/font_size_default_input" />
Now Im using:
<myapp.app.widgets.edittext.MyCustomEditText
android:id="#+id/panEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/dimen_8_dp"
android:hint="PAN number"
android:imeOptions="actionNext"
android:inputType="textCapCharacters"
android:maxLength="10"
android:text="#{viewModel.pan}"
android:textSize="#dimen/font_size_default_input" />
Now this doesnt work.
my method
!viewModel.isPanValid() -> binding.panEditText.setError(viewModel.panError.value)
doesnt work but for email it works what to do?
the
MyCustomEditText is just en extended class
public class MyCustomEditText extends LinearLayout implements View.OnFocusChangeListener, TextWatcher, TextView.OnEditorActionListener, View.OnClickListener {
It includes just a UI stuff and on focus listener etc
setError is a function of EditText. Your MyCustomEditText is not an EditText but a LinearLayout so you can't call setError on it because it simply doesn't exist for that class. I don't know the rest of MyCustomEditText but I assume it has an EditText inside it and you might have a reference to it, say editTextInThisClass. If not you will need to create one. Then you could write this in your MyCustomEditText:
public void setError(CharSequence error) {
editTextInThisClass.setError(error)
}
but I wonder if you actually intended for it to be a LinearLayout. If not you should just change LinearLayout to EditText
Surely a simple question to ask but I've tried for hours and I can't seem to get the problem !
I have a DialogFragment which contains a
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/interval_input_layout"
style="#style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:boxStrokeWidth="0dp">
<AutoCompleteTextView
android:id="#+id/time_interval_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none"
tools:ignore="LabelFor" />
</com.google.android.material.textfield.TextInputLayout>
This is the listener set on this AutoCompleteView
binding.untilInput.onItemClickListener =
AdapterView.OnItemClickListener { parent, view, position, id ->
when (position) {
0 -> {
binding.numberLayout.visibility = View.GONE
}
1 -> {
binding.numberLayout.visibility = View.GONE
}
2 -> {
binding.numberLayout.visibility = View.VISIBLE
}
}
}
While number layout is just a linear layout like this
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/number_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="For number of events"
android:textColor="?android:textColorSecondary" />
</androidx.appcompat.widget.LinearLayoutCompat>
At first the listener wasn't being called so I set it like this instead of directly calling the function setOnItemClickListener (don't know why that wasn't working) , Now the listener is being called , I even put a breakpoint and debugged it and its setting visibility but its not taking any effect and it does not cause any error so I can't seem to get the problem here
Using a DialogFragment I inflated the view layout with the use of databinding in the method OnCreateView & then in OnViewCreated I worked with my view and caused changes to UI and set listeners to it and again cause changes to UI
in OnCreateDialog I called both of these methods onCreateView (to get the view and set it to dialog) and onViewCreated to setup the view
I tried to find the view using findViewById just to ensure if the databinding was working fine and it was working fine but visibility still won't change and the view won't update !
I still have't gotten to the root of the problem but it seems you have to store the view inside a variable so you don't lose a reference to it when onClickListener is called and in my opinion just when the onClickListener is called getting the view from the binding becomes invalid and it should but the small problem is that I am not calling onDestroy to make the binding null because the binding was invalid at that time !
Now I am just storing a refrence to binding like this
val myvar = binding.monthLayout
and I am capturing the value of myvar inside the onClickListener rather than using the binding
I am using data binding for setting data to recyclerview item and I am using #BindingAdapter for custom attrinbutes.
Now i want to update the text of a textview in each second. The textview is displaying a text(time ago) with related to a timestamp, i have created a #BindingAdapter function by passing the timestamp, which works perfectly for setting the text single time, but i want to update it in each second.
<TextView
android:id="#+id/tvTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textStyle="italic"
app:timeago="#{order.DateStamp}"
app:layout_constraintBottom_toTopOf="#id/tvOrderId"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Just now" />
Following is my binding adapter
#BindingAdapter("timeago")
public static void setTimeAgo(TextView view, long time) {
view.setText(getTimeAgo(time));
}
this is my layout file
You can use EchoBind class, BindingAdapter for this.
The binding should be in two way from XML to model/adapter or model/adapter to XML.
To get detailed documentation refer these link1 & link2.
I'm new to Android programming, and I'm trying to make a simple button which displays a toast notification when clicked.
I tried to initialize a button called "button" in my MainActivity like so:
public class MainActivity extends Activity implements View.OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button =(Button)findViewById(R.id.button1);
button.setOnClickListener(this);
}
public void onClick(View v){
Toast toast = Toast.makeText(this, "Click Me", Toast.LENGTH_LONG);
toast.show();
}
}
Also, here is activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/button1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/button1">
</Button>
</RelativeLayout>
UPDATE: findViewById now works fine after importing android.R. However, this created a new error when I call setContentView(R.layout.activity_main);
Okay a bit of background here. strings.xml is for defining pieces of text. For instance the text that might go on a button (but this does not define the button itself).
The button is going to have to be defined in a layout file in the res/layout/ directory. Yours is likely called activity_main.xml.
You'll need to create a button element in this file and assign the id to something descriptive. This kind of id is what findViewById is going to search on.
An example:
<Button
android:id="#+id/thebuttonsid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="96dp"
android:text="#string/button1" />
You can get a handle to this button like so:
Button button = (Button)findViewById(R.id.thebuttonsid);
Notice how I set the text to #string/button1? This is what the strings.xml file is for. However the layout files in the layout directory are where you define controls like buttons.
The button's ID name is same to the button's text name. You'd better change any one to other name.It must be work.
I would clean the project and build again. Or reimport the project. Eclipse is ... just hard to use. Try to use Android Studio.
When there is some "mismatch" with resources cleaning a project is a good advice. IN the past it was even more so.
Next what I would check if your resources compile as such. You might have an error somewhere in your resources, therefore the R does net get compiled and any reference to R.id.* is not valid.
I currently have an activity with some buttons.
In my xml, buttons are defined like this:
<ImageButton (...) android:onClick="GoToPageX"/>
and I have in my activity:
public void GotoPageX() {
startActivity(new Intent(this, PageX.class));
finish();
}
The problem is that I have hundreds of buttons and do not want to write
<ImageButton (...) android:onClick="GoToPage1"/>
<ImageButton (...) android:onClick="GoToPage2"/>
<ImageButton (...) android:onClick="GoToPage3"/>
...
<ImageButton (...) android:onClick="GoToPage100"/>
and all the scripts.
I am now using
public void GotoPage( int i) {
startActivity(new Intent(getBaseContext(), activities.get(i)));
finish();
}
and would like to give the parameter i from the xml, is that possible?
Thank a lot for any help.
It is not directly possible. However, maybe you could use android:tag to get your parameter.
<ImageButton (...) android:onClick="goToPage" android:tag="25"/>
public void goToPage(View v) {
String pageNumber = v.getTag().toString();
/* ... */
}
You could also do this by enabling data binding and using a lambda expression for the onClick value. This way is especially useful if you plan to use multiple inputs of different types. Here's an example of a simple MainActivity.xml in which this strategy is used.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="main" type="com.example.android.myapp.MainActivity" />
</data>
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton (...) android:onClick='#{() -> main.GotoPage(1,"one")}'/>
<ImageButton (...) android:onClick='#{() -> main.GotoPage(2,"two")}'/>
<ImageButton (...) android:onClick='#{() -> main.GotoPage(3,"three")}'/>
...
<ImageButton (...) android:onClick='#{() -> main.GotoPage(100,"one hundred")}'/>
</LinearLayout>
</layout>
and in MainActivity.java
public void GotoPage(int i, String otherVariable) {
/** code using i and otherVariable **/
}
UPDATE: For those who don't know how to set up data binding, I will explain it here so you don't have to google around for it. First, enable dataBinding in the build.gradle file:
android {
...
dataBinding {
enabled = true
}
...
}
Also, make sure jcenter() is in your repositories.
Then, go to the XML of the layout where onClick will be used and wrap its layout in a layout tag with a data section like this:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="main" type="com.example.android.yourapp.MainActivity" />
</data>
<YourLayout>
...
</YourLayout>
</layout>
For the variable tag's type parameter, you need to put the class that will contain the function which onClick points to. In this example, I will use the main activity class, which is named MainActivity in my test project.
After you have your layout wrapped in a layout tag like in the example above, clean the project in Android Studio. You may also need to invalidate cache/restart or close and reopen Android Studio.
Next, if the the layout with onClick you are trying to set up data binding for is the same layout set by setContentView in your main activity class, open the file that contains your main activity class. If the layout with onClick you are trying to set up data binding for is inflated programmatically in a different file, open the file in which the layout is inflated instead.
Add these imports to that file:
import com.example.android.yourapp.databinding.YourLayoutBinding;
import android.databinding.DataBindingUtil;
That first class you are importing is generated when you clean the project (and possibly have to invalidate cache/restart) and is automatically named after the XML file you added the layout wrapper to. If the layout file is named your_layout.xml, the import class will be named YourLayoutBinding. The exact import path will depend on your app name and structure, but it will always be within a databinding parent class.
The next step depends on whether the layout you are adding data binding to is set with setContentView or is inflated with inflate. Both versions of the following step make use of the method setMain. The setMain method is automatically generated and named using the value of the name parameter in the layout wrapper we added. Since we put name="main", the method is called setMain.
If the layout you are adding data binding to is the same layout set by setContentView find the line in your main activity class that looks like setContentView(R.layout.your_layout); and change it to use DataBindingUtil.setContentView instead of setContentView, adding this as its first argument. Use binding.setMain to point the layout's main variable to the current activity.
YourLayoutBinding binding = DataBindingUtil.setContentView(this, R.layout.your_layout);
binding.setMain(this);
If the layout you are adding data binding to is not set by setContentView but rather inflated go to where it is inflated in your code. It should look something like this:
return inflater.inflate(R.layout.your_layout, container, false);
Modify it to use DataBindingUtil.inflate, adding the previous inflater as its first argument. Use binding.setMain to point the layout's main variable to the main activity, and use binding.getRoot() to get the view. It should end up like this:
YourLayoutBinding binding = DataBindingUtil.inflate(inflater, R.layout.your_layout, container, false);
binding.setMain((MainActivity) getActivity());
return binding.getRoot();
Now the data binding is ready to use. Add a function for onClick to point to within your main activity class.
public void exampleFunction(int number, String text) {
System.out.println("Number: " + number + ", Text: " + text);
}
You can call it from the layout you added data binding to using a lambda expression. This example function doesn't require a View, so it can be used like this:
<Button android:id="#+id/buttonID"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="26sp"
android:text="Test"
android:onClick='#{() -> main.exampleFunction(123, "test")}'/>
Make sure to use single quotes around the value for onClick if you plan on using a String input.
If you do need to pass the button's view to your function, simply add a View parameter to your function's required arguments and use a lambda expression like this instead:
<Button android:id="#+id/buttonID"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="26sp"
android:text="Test"
android:onClick='#{(view) -> main.exampleFunction(view, 123, "test")}'/>
If you will create some layout element in xml you can use there
<ImageButton
android:id="#+id/some_id_value" />
where some_id_value is kind of unique string which will be translate into id which is kept in R.java (better for you- don't change anything there) than in code you can get that id by using
R.id.some_id_value
read a little bit there that's really basics.
You can set Tags for a view. Tags are basically a way for views to have memories.
xml:
<ImageButton
...Other Parameters...
android:id="#+id/Button2"
android:tag="2"
android:onClick="GoToPageX"/>
<ImageButton
...Other Parameters...
android:id="#+id/Button3"
android:tag="3"
android:onClick="GoToPageX"/>
The line android:tag="2" set a tag value of 2(string data type) to Button2
Java file:
General Case:
Inside GoToPageX(View v) function,
use v.getTag() to get the tag value of corresponding view(From which ever view the method was called).
Your case:
Add the method as follows
public void GoToPageX(View v){
int i = Integer.parseInt(v.getTag()); //parseInt converts string to integer
startActivity(new Intent(getBaseContext(), activities.get(i)));
finish();
}