IntegerView instead of TextView - android

I have an Integer that I want to display in a TextView. Instead of having Textview foo and int foo with the same number all the time, I was hoping there was a way to do something like IntegerView. (A TextView that only takes integers) or that serves the same purpose. Please ask if you need clarification. My objective is to keep my code clean instead of either parsing 100 variables or having 200 variables instead of 100.
Simplification:
In class A, I have int a. I want to display int a in a TextView and then send it to class B. I want to keep my code as clean and elegant as possible. Suggestions?
Coding:
private TextView tvFoo;
private int foo;
public void thing(){
tvFoo.setText("" + foo);
DifferentClass.someMethod(foo);
}
<TextView
android:id="#+id/tvFoo" />
**I have a lot of variables to mess with, so I am trying to eliminate one of the 2.
Thanks!

Just subclass TextView.
public class IntegerView extends TextView {
...
public void setInt(int value) {
setText(String.valueOf(value));
}
public int getInt() {
return Integer.valueOf(getText().toString());
}
}
Put it in your xml layouts this way:
<com.package.to.IntegerView android:id="#+id/intView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

I would recommend you use the NumberPicker from this library.
https://github.com/derekbrameyer/android-betterpickers

Related

Two way data binding with two EditText views

I'm having trouble making two Edit Text views that update when one is changed. To provide some context, see the following image:
Also the view in action (can't have it embedded apparently.):
https://i.imgur.com/an6Kodx.mp4
Here, we add targets (T1, T2, T3 etc.), then draw an arc and user may set start and finish points of the camera (gray and red icons respectively.) Then, we get the total move value (in degrees). This value will determine amount the motor will rotate (The app is basically a controller for users to have automated photo-shoots).
What I try to achieve is that, when user enters a photo number, right edittext divides total move degrees to that count and show angle per photo and vice-versa.
However, I'm a bit lost among all the online content demonstrating various examples (like password strength etc.)
I've included DataBinding on gradle.
I've created a custom class (RotaryPhotoShoot) to have a model of three main parameters (angle per shoot, number of photos and total move).
I've moved my cosntraint layout to layout root.
I've created data as seen on following code blocks.
RotaryPhotoShoow.java (my model)
package com.example.macrorecapp.models;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
public class RotaryPhotoShoot extends BaseObservable {
private static final String TAG = "Rotary Photo Shoot";
private float anglePerPhotos;
private int numberOfPhotos;
private int totalMoveDegrees;
public RotaryPhotoShoot(float anglePerPhotos,int numberOfPhotos, int totalMoveDegrees) {
this.anglePerPhotos = anglePerPhotos;
this.numberOfPhotos = numberOfPhotos;
this.totalMoveDegrees = totalMoveDegrees;
}
#Bindable
public float getAnglePerPhotos() {
return anglePerPhotos;
}
#Bindable
public int getNumberOfPhotos() {
return numberOfPhotos;
}
#Bindable
public int getTotalMoveDegrees() {
return totalMoveDegrees;
}
#Bindable
public void setAnglePerPhotos(float anglePerPhotos) {
this.anglePerPhotos = anglePerPhotos;
}
#Bindable
public void setNumberOfPhotos(int numberOfPhotos) {
this.numberOfPhotos = numberOfPhotos;
}
#Bindable
public void setTotalMoveDegrees(int totalMoveDegrees) {
this.totalMoveDegrees = totalMoveDegrees;
}
}
activity_rotary_photo_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="photoShoot"
type="com.example.macrorecapp.models.RotaryPhotoShoot" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/appMainBackground"
tools:context=".features.rotary.RotaryPhotoSettings">
...
<com.example.macrorecapp.features.shared.views.RotaryView
android:id="#+id/rotaryPhotoView"
android:layout_width="360dp"
android:layout_height="360dp"
app:isClockwise="true"
app:targetList="#array/targets"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/h_guideline1"
app:layout_constraintBottom_toTopOf="#id/h_guideline2" />
<EditText
android:id="#+id/numberOfPhotosEdittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{``+photoShoot.numberOfPhotos}"
android:textAlignment="center"
android:ems="4"
android:textSize="15sp"
android:textColor="#FFFFFFFF"
app:layout_constraintBottom_toTopOf="#+id/numberOfPhotosSubtext"
app:layout_constraintEnd_toStartOf="#id/v_guideline"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/numberOfPhotosBG"
android:importantForAutofill="no"
android:inputType="number" />
...
<EditText
android:id="#+id/anglePerPhotosEdittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{``+photoShoot.anglePerPhotos+(char) 0x00B0}"
android:textAlignment="center"
android:ems="4"
android:textSize="15sp"
android:textColor="#FFFFFFFF"
app:layout_constraintBottom_toTopOf="#+id/anglePerPhotosSubtext"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#id/v_guideline"
app:layout_constraintTop_toTopOf="#+id/anglePerPhotosBG"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
And finally RotaryPhotoSettings.java
package com.example.macrorecapp.features.rotary;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import com.example.macrorecapp.R;
import com.example.macrorecapp.databinding.ActivityRotaryPhotoSettingsBinding;
//import com.example.macrorecapp.features.shared.views.RotaryView;
import com.example.macrorecapp.models.RotaryPhotoShoot;
public class RotaryPhotoSettings extends AppCompatActivity {
private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.2F);
//RotaryView mPhotoRotaryView;
//private int mTotalMoveInDegrees;
ActivityRotaryPhotoSettingsBinding mBinding;
RotaryPhotoShoot mRotaryPhotoShoot;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_rotary_photo_settings);
mRotaryPhotoShoot = new RotaryPhotoShoot(6.88f, 25, 178);
mBinding.setPhotoShoot(mRotaryPhotoShoot);
//mPhotoRotaryView = findViewById(R.id.rotaryPhotoView);
//mPhotoRotaryView.addTarget(300);
//mTotalMoveInDegrees = mPhotoRotaryView.getTotalMoveInDegrees();
}
public void goBack(View view) {
view.startAnimation(buttonClick);
finish();
}
public void openThreeSixtyPhotoRotary(View view) {
}
}
Currently I have no errors whatsoever and I'm sure I'll be able change views one way when I programmatically set them in activity. What I feel like I should do is, first use #={} syntax in xmls to begin with. Then I may need to have custom adapters or binders. I've also seen that people use ObservableInt etc. which I got a bit lost. I needed to set my getTotalMove function to set static to get it from RotaryView.java but from then on I couldn't progress.
I'd like to have some pointers what to do onward. I think I can easily handle rounding up numbers where I implement the custom binder/adapter. I know for example the angle may be decimal while the photo count needs to be integer. I will be rounding up photo count and change the angle itself to closest possible value once it is done being edited. I will also need to determine whether start and end points will be included in the interval. Like, for 100 degrees, with 20 degrees per shoot, it'd be like this:
0: S__S__S__S__S__S :100 Thus 6 photos etc.
Before I implement any listeners etc., I figured I could ask here first, because obviously point of using the Data Binding library is to get rid of bunch of listeners and so on. I would appreciate some sort of example where two EditText views change eachother.
Once I figure out how to set non-edited EditText, I'll be dealing with extra considerations I mentioned above, but first I need to get done with two way binding part. I suppose this "two way" is between view and view model, not directly between views, obviously. So I don't know if I can have a trick like #={``+photoShoot.totalMove/photoShoot.anglePerPhoto} etc. in xml.
Anyways, the post is much longer than it is supposed to be, my apologies.
This looked pretty straight-forward at first glance, but the more I look into it, the more complicated it gets. Maybe I'm just confusing myself.
I'd like to add some partial-answer to my own question. I tried to adjust info that I had from following link in my own use case:
https://www.bignerdranch.com/blog/two-way-data-binding-on-android-observing-your-view-with-xml/
I managed to change angle box (one on the right) with following changes:
I deleted some unnecessary variables in my custom view you see above and added a public "Total Move" getter. I use this in my model class RotaryPhotoShoot.
I also added #={} in my xml as you can see updated code below. This combined with notifyPropertyChanged(com.example.macrorecapp.BR.numberOfPhotos); made it possible to update angle box.
Before adding another wall of text, I'll just add the relevant parts of my code for further reference to other people.
RotaryPhotoSettings.java (The activity class that utilizes binding.)
package com.example.macrorecapp.features.rotary;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import com.example.macrorecapp.R;
import com.example.macrorecapp.databinding.ActivityRotaryPhotoSettingsBinding;
import com.example.macrorecapp.models.RotaryPhotoShoot;
public class RotaryPhotoSettings extends AppCompatActivity {
private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.2F);
//RotaryView mPhotoRotaryView;
//private int mTotalMoveInDegrees;
ActivityRotaryPhotoSettingsBinding mBinding;
RotaryPhotoShoot mRotaryPhotoShoot;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_rotary_photo_settings);
mRotaryPhotoShoot = new RotaryPhotoShoot(6.88f, 25);
mBinding.setPhotoShoot(mRotaryPhotoShoot);
//mPhotoRotaryView = findViewById(R.id.rotaryPhotoView);
//mPhotoRotaryView.addTarget(300);
//mTotalMoveInDegrees = mPhotoRotaryView.getTotalMoveInDegrees();
}
public void goBack(View view) {
view.startAnimation(buttonClick);
finish();
}
public void openThreeSixtyPhotoRotary(View view) {
}
}
My model class, RotaryPhotoShoot.java
package com.example.macrorecapp.models;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import com.example.macrorecapp.features.shared.views.RotaryView;
public class RotaryPhotoShoot extends BaseObservable {
private static final String TAG = "Rotary Photo Shoot";
private float anglePerPhotos;
private int numberOfPhotos;
public RotaryPhotoShoot(float anglePerPhotos, int numberOfPhotos) {
this.anglePerPhotos = anglePerPhotos;
this.numberOfPhotos = numberOfPhotos;
}
#Bindable
public float getAnglePerPhotos() {
return RotaryView.getTotalMoveInDegrees()/(float) numberOfPhotos;
}
#Bindable
public int getNumberOfPhotos() {
return numberOfPhotos;
}
#Bindable
public void setAnglePerPhotos(float anglePerPhotos) {
this.anglePerPhotos = RotaryView.getTotalMoveInDegrees()/numberOfPhotos;
}
#Bindable
public void setNumberOfPhotos(int numberOfPhotos) {
this.numberOfPhotos = numberOfPhotos;
notifyPropertyChanged(com.example.macrorecapp.BR.numberOfPhotos);
notifyPropertyChanged(com.example.macrorecapp.BR.anglePerPhotos);
}
}
The activity layout file that have views in it, activity_rotary_photo_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="photoShoot"
type="com.example.macrorecapp.models.RotaryPhotoShoot" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/appMainBackground"
tools:context=".features.rotary.RotaryPhotoSettings"
android:focusable="true"
android:focusableInTouchMode="true">
<com.example.macrorecapp.features.shared.views.RotaryView
android:id="#+id/rotaryPhotoView"
android:layout_width="360dp"
android:layout_height="360dp"
app:isClockwise="true"
app:targetList="#array/targets"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/h_guideline1"
app:layout_constraintBottom_toTopOf="#id/h_guideline2" />
<EditText
android:id="#+id/numberOfPhotosEdittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#={``+photoShoot.numberOfPhotos}"
android:textAlignment="center"
android:ems="4"
android:textSize="15sp"
android:textColor="#FFFFFFFF"
app:layout_constraintBottom_toTopOf="#+id/numberOfPhotosSubtext"
app:layout_constraintEnd_toStartOf="#id/v_guideline"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/numberOfPhotosBG"
android:importantForAutofill="no"
android:inputType="number" />
<EditText
android:id="#+id/anglePerPhotosEdittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{``+String.format(`%.2f`, photoShoot.anglePerPhotos)+(char) 0x00B0}"
android:textAlignment="center"
android:ems="4"
android:textSize="15sp"
android:textColor="#FFFFFFFF"
app:layout_constraintBottom_toTopOf="#+id/anglePerPhotosSubtext"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#id/v_guideline"
app:layout_constraintTop_toTopOf="#+id/anglePerPhotosBG"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Current problems that I could use some markers:
I need cross changes, currently I don't know how to tell whether a change is coming from the EditText being changed by typing or not. When the change is coming from other box, I will format/round the value properly and update the EditText view.
I could just use a bool value that I would toggle depending on whether the change is coming from manual editing or value changing progromatically. This would help me prevent infinite loop. However, as I said above, I am not sure what to listen to in order to achieve that.
Another behavior I would like to have is that, when camera start-finish icons are moved and TotalMove (in degrees) changed, I want to have numberOfPhotos fixed and update anglePerPhotos only. I may need to add binding in RotaryView.java for that. If this is an overkill, I may just add a trigger/listener on RotaryPhotoShoot. Currently. when I make a change in numberOfPhotos after I change the camera positions, angle is calculated properly as expected.
One little bug(?) I have is that, I cannot delete the last digit in numberOfPhotos field. See the following webm video below:
https://gfycat.com/distortedyoungdairycow
One thing I've realized is that, getter and setters in model class alone achieves what I need to do. This indeed removes the need to mess around with listeners and custom adapters. Since I'm using two EditTexts interchangeably, I may end up using them still.
Note that you can use any built-in Java functions (see string formatting I used in anglePerPhotos field). If necessary, I know how to import a class in <data></data> block.
I'll add one more link before I finish this update-answer for those who may be lost how to set if Data Binding in their project for the first time:
https://www.youtube.com/watch?v=v4XO_y3RErI
This solved my problem:
android:text="#{String.valueOf(product.quantityInventory + product.quantityShop)}"

Text Watcher Binding Adapter with ViewModel

I'm still new to all this MVVM and Android Architecture Components. I have a few screens (Login and Register) that have inputs for email, password, name etc and a 'continue' button that's only enabled when the required fields are filled out correctly. There's also text views for messages such as "password must be..." and "not a valid email...". I'm trying to use a binding adapter and viewmodel to pull some of this validation logic out of my MainActivity and away from my business logic, but I'm struggling. I'm not even sure if this is the best way to do it. My thought with the ViewModel is that it would hold it's state on rotation/activity changes.
RegisterActivity is an Activity that simply holds a ViewPager with 3 fragments (email/password, first/last name, validation code).
Binding Adapter
#BindingAdapter("app:onTextChanged")
public static void onTextChanged(TextInputEditText view, TextViewBindingAdapter.OnTextChanged listener) {
}
Layout
<TextView
android:id="#+id/tv_error_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="#string/register_email_requirement"
android:textColor="#color/moenPrimaryError"
android:textSize="18sp"
android:visibility="#{viewModel.emailValidationVisible ? View.VISIBLE: View.GONE}"
app:layout_constraintBottom_toTopOf="#id/input_layout_password"
app:layout_constraintEnd_toEndOf="#+id/input_layout_email_address"
app:layout_constraintStart_toStartOf="#+id/input_layout_email_address"
app:layout_constraintTop_toBottomOf="#+id/input_layout_email_address"
app:layout_goneMarginTop="16dp" />
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/input_email_address"
style="#style/MoenTextInputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
app:onTextChanged="#{viewModel.onTextChanged}"
app:onFocusChange="#{inputLayoutEmailAddress}">
</com.google.android.material.textfield.TextInputEditText>
ViewModel
public class RegisterFragmentViewModel extends BaseObservable {
private boolean emailValidationVisible = false;
#Bindable
public boolean getEmailValidationVisible() {
return this.emailValidationVisible;
}
public void toggle() {
this.emailValidationVisible = !this.emailValidationVisible;
notifyPropertyChanged(BR.viewModel);
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.w("tag", "onTextChanged " + s);
this.toggle();
}
}
This is just a test I have. My thought was that I could bind the TextView visibility to a boolean that I can toggle/manipulate with a onTextChanged listener, but I don't know how to wire up the Binding Adapter. Am I on the right path? Is there a better/easier way to do this?
Am I on the right path? Is there a better/easier way to do this?
it is a way of doing it. I would remove the ternary operator from this line
android:visibility="#{viewModel.emailValidationVisible ? View.VISIBLE: View.GONE}"
and create a simple function in your VM that returns it. EG:
#Bindable
public int getVisibility() {
return emailValidationVisible ? View.VISIBLE: View.GONE
}
and in toggle(), you will have something like
public void toggle() {
this.emailValidationVisible = !this.emailValidationVisible;
notifyPropertyChanged(BR.visibility);
}
which will call the getter for you. Your xml will have to be changed like follow
android:visibility="#{viewModel.getVisibility()}"
Alternately you could create a BindingAdapter that takes a Boolean and change the visibility accordingly to it

Problems changing TextView's text inside a listener

I'm trying to make a TextView look like a timer and control the time displayed with a SeekBar.
First, I get the message the TextView must be a Final but when I change that I can't change the TextView with setText in the listener.
How can I fix this code?
SeekBar seekBar = findViewById(R.id.seekBar);
final TextView timeView = findViewById(R.id.timeView);
seekBar.setMax(600);
seekBar.setProgress(30);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int minutes = progress / 60;
int seconds = progress - (progress * 60);
timeView.setText(Integer.toString(minutes), ":", Integer.toString(seconds));
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
Try to create a public Textview.
So replace this line
final TextView timeView = findViewById(R.id.timeView);
With
timeView = findViewById(R.id.timeView);
and add this
TextView timeView;
Over your OnCreate method.
The only problem with your code is the syntax of setText() method.
setText() takes one String (CharSequence) as an argument, so change this:
timeView.setText(Integer.toString(minutes), ":", Integer.toString(seconds));
to this:
timeView.setText(Integer.toString(minutes) + ":" + Integer.toString(seconds));
replace
timeView.setText(Integer.toString(minutes), ":", Integer.toString(seconds));
to
timeView.setText(Integer.toString(minutes)+ ":"+ Integer.toString(seconds));
Indeed the simple solutions is to simply change the line of code where the OP wishes to use setText() inside the onProgressChanged() method: There is no override for the setText() method that handles those parameters. Simple solution(as stated in many answers):
timeView.setText(Integer.toString(minutes) + ":" + Integer.toString(seconds));
But...digging deeper
TL;DR
Originally, the OP wanted to simply use TextView timeView in the onCreate() method, but was warned by the compiler that they needed to add final in front of TextView timeView in order to be able to use timeView inside the anonymous inner class SeekBar.OnSeekBarChangeListener().
However, in general, the key word final indicates that the variable cannot be altered after initialization. Although a bit confusing in this special case using final will allow changes to the TextView using setText().
The primary problem is scope. SeekBar.OnSeekBarChangeListener() is an anonymous inner class and onCreate() is the enclosing block. This (basically) means that the inner class does not actually belong to onCreate() and that timeView is outside the scope of the method onProgressChanged().
Certainly, adding final to the method variable TextView timeView will "fix" the problem--in this special case (and some like it), but not all cases; therefore, I believe that using final is counter-intuitive.
Consider a variable int count = 0 or String showTime = "Show time"; interior to onCreate() but outside the anonymous inner class. The compiler will again throw a warning that the variables must be declared final if they are to be used within the anonymous inner class. But by doing so, they can no longer be altered. In fact, the code will not even compile if one were to attempt to change the values. By making TextView timeView; a class variable (ie. moving it outside the onCreate() method) the scope of this field will increase to include the anonymous inner class. The same is true for the variable int count = 0 or String showTime = "Show time";--making them class variable would also increase their scope to include the anonymous inner class so that they can be used and altered inside the method onProgressChanged(). Therefore, it is my opinion that using class variables instead of final is more intuitive.
Check the Java Docs:
Anonymous Classes
Accessing Members of an Enclosing Class

Can I have BindingAdapters with overlapping value sets?

Let's say I have this view model with methods:
public int getValueA() {
return a;
}
public int getValueB() {
return b;
}
#BindingAdapter("valueA")
public void setupSomething(View view, int valueA) {
// do something with a
}
#BindingAdapter({"valueA", "valueB"})
public void setupSomethingElse(View view, int valueA, int valueB) {
// do something with a and b
}
and I bind this to a view:
<View
android:layout_width="match_parent"
android:layout_height="wrap_content"
bind:valueA="#{viewmodel.valueA}"
bind:valueB="#{viewmodel.valueB}"/>
How can I call both BindingAdapter methods? Right now data binding is just calling the later. I guess I could just call setSomething from within setSomethingElse but this smells a little fishy to me (and partially defeats the purpose of databinding).
It's like you're suggesting yourself: you need to call setupSomething() from setupSomethingElse. It's just fine doing so and how databindings work. Only the best fitting #BindingAdapter will be used for your attributes.
Alternatively you can use the requireAll() field of #BindingAdapter. But this is only feasible if you can handle the Java default value (in your case 0) for your values.
Whether every attribute must be assigned a binding expression or if some can be absent. When this is false, the BindingAdapter will be called when at least one associated attribute has a binding expression. The attributes for which there was no binding expression (even a normal XML value) will cause the associated parameter receive the Java default value. Care must be taken to ensure that a default value is not confused with a valid XML value.
#BindingAdapter({"valueA", "valueB"}, requireAll = false)
public void setupSomethingElse(View view, int valueA, int valueB) {
if (valueA != 0) {
// do something with a
if (valueB != 0) {
// do something with a and b
}
}
}
So you don't need setupSomething() anymore. But personally I like the first approach better.

Seekbars and EditTexts

I am working on an application in which I need the user to set an array of 30 values and to make it user friendly and easy to use I have decided to use a series of SeekBars and EditText widgets. I am using eclipse and have used it to set up the layout.
I am looking for an efficient way to set up the application to automatically update the value of the SeekBar when the value of the EditText has been changed and then use that same value in a application integer array.
<SeekBar android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:max="255"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:padding="10dp"
android:id="#+id/seekX"></SeekBar>
<EditText android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".01"
android:minWidth="50sp"
android:maxWidth="50sp"
android:gravity="center_horizontal"
android:padding="10dp"
android:layout_marginRight="10dp"
android:inputType="number"
android:id="#+id/editX"></EditText>
The seek bars and EditText fields are named in a corresponding way editX should match seekX as editY should match seekY and so on. I am also storing the values in the int[] upgradeValues.
I have also set the SeekBar to have a max of 255 but i need a way to automatically change any value set in the EditText field above 255 down to 255 and similarly any value below 0 to 0.
Basically I need an efficient way of making "(ValueOF)seekX = (ValueOf)editX = (ValueOf)upgradeValues[x] >= 0 <= 255" and be updated if seekX or editX is changed.
I am still pretty new to Android development, so this answer isn't very specific, but hopefully it gets you on your way.
There are a few approaches. You can set change listeners on both of your seekbar and the edittext that update the values of the other (suppose you have your EditText t, SeekBar b and the value in model:
b.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
{
#Override
public void onProgressChanged(final SeekBar seekBar,
final int progress,
final boolean fromUser)
{
if (fromUser)
{
model = progress;
updateUI();
}
}
#Override
public void onStartTrackingTouch(final SeekBar seekBar)
{
}
#Override
public void onStopTrackingTouch(final SeekBar seekBar)
{
}
});
t.setOnKeyListener(new View.OnKeyListener()
{
#Override
public boolean onKey(final View v,
final int keyCode,
final KeyEvent event)
{
model = Integer.parseInt(t.getText().toString());
updateUI();
return true;
}
});
Then updateUI() would be something like:
private void updateUI()
{
t.setText(model);
b.setProgress(model);
}
Those are some crazy names and I clearly did no error checking. But you get the idea. This is probably NOT the way you want to go, because you have to make sure you catch all the different ways the user interacts with each component (onKey probably isn't enough to detect whenever the EditText value changes).
The proper (MVC) way is to have your model (your int[]) contain the value and have your SeekBar and EditText use your model as their models. I don't know how to do that in Android's UI model.

Categories

Resources