I'm currently working on 100 Random Facts app that simply displays a new fact when the button is clicked. Every time a new fact is displayed the same screen pops up but with a different color as the background. I did this by storing the facts in an array and also the colors in an array and then randomly matching them, i want to do this but with images instead. How can I change the background to a customized image when a random fact pops up. So that each time the new fact button is pressed a fact pops up but instead of the background being a color, being an random image instead?
Any help is appreciated!
Here is my code, The Different Colors are stored in a java class called ColorWheel
ColorWheel.java
package com.example.android.funfacts;
import android.graphics.Color;
import java.util.Random;
public class ColorWheel {
//Member variable (propoerties about the object)
public String[] mColors = {
"#39add1", // light blue
"#3079ab", // dark blue
"#c25975", // mauve
"#e15258", // red
"#f9845b", // orange
"#838cc7", // lavender
"#7d669e", // purple
"#53bbb4", // aqua
"#51b46d", // green
"#e0ab18", // mustard
"#637a91", // dark gray
"#f092b0", // pink
"#b7c0c7" // light gray
};
String color="";
//Method (abilities:things the object can do)
public int getColor(){
//Randomly select a fact
Random randomGenerator =new Random(); // construct a new random generator
int randomNumber =randomGenerator.nextInt(mColors.length);
color = mColors[randomNumber];
int colorAsInt = Color.parseColor(color);
return colorAsInt;
}
}
FunFactsActivity.java
public class FunFactsActivity extends Activity {
public static final String TAG =FunFactsActivity.class.getSimpleName();
private FactBook mFactBook = new FactBook();
private ColorWheel mColorWheel= new ColorWheel();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fun_facts);
// Declare our view variables and assign them the views from the layout file
final TextView factLabel = (TextView) findViewById(R.id.factTextView);
final Button showFactButton= (Button) findViewById(R.id.showFactButton);
final RelativeLayout relativelayout =(RelativeLayout) findViewById(R.id.relativeLayout);
View.OnClickListener listener= new View.OnClickListener() {
#Override
public void onClick(View view) {
String fact = mFactBook.getFact();
//Update the label with our dynamic fact
factLabel.setText(fact);
int color = mColorWheel.getColor();
relativelayout.setBackgroundColor(color);
showFactButton.setTextColor(color);
}
};
showFactButton.setOnClickListener(listener);
//Toast.makeText(this,"YAY! our activity was created",Toast.LENGTH_LONG).show();
Log.d(TAG, "We are Logging from the oncreate method");
}
}
activity_fun_facts.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.austinzeller.funfacts.FunFactsActivity"
android:background="#drawable/image1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/did_you_knoww"
android:textSize="24sp"
android:textColor="#android:color/background_light"
android:textStyle="normal|bold" />
<Button
android:text="#string/new_random_fact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/showFactButton"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="#android:color/background_light"
android:textColor="#51b46d" />
<TextView
android:text="#string/ants_stretch_when_they_wake_up_in_the_morningg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/factTextView"
android:textColor="#android:color/background_light"
android:textSize="21sp"
android:layout_above="#+id/showFactButton"
android:layout_centerHorizontal="true"
android:layout_marginBottom="129dp"
android:textStyle="normal|bold" />
</RelativeLayout>
FactBook.java
package com.example.android.funfacts;
import java.util.Random;
public class FactBook {
//Member variable (propoerties about the object)
public String[] mFacts = {
"There are 206 bones in the human body!",
"Left-handed people are better at sports that require good spatial
judgment and fast reaction, compared to right-handed individuals.",
"Your heart beats over 100,000 times a day!",
"One quarter of the human brain is used to control the eyes.",
"Europe is the only continent without a desert.",
"The tongue is the strongest muscle in the human body.",
"Food can only be tasted if it is mixed with saliva.",
"About 3000 years ago, most Egyptians died by the time they were
30!",
"Under extreme stress, some octopuses will eat their own arms.",
"A fully loaded supertanker traveling at normal speed takes a least
twenty minutes to stop.",
"Aluminum used to be more valuable than gold!",
"More than half the population of Kenya is under the age of 15."
built." };
String fact="";
//Method (abilities:things the object can do)
public String getFact(){
//Randomly select a fact
Random randomGenerator =new Random(); // construct a new random generator
int randomNumber =randomGenerator.nextInt(mFacts.length);
fact = mFacts[randomNumber];
return fact;
}
}
Related
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)}"
I'm a very beginner in Android. I would like to print this in TextView, but the screen is all white and i can't see content of TextView. In the console works properly. Below is my activity and layout file.
public class MainActivity extends AppCompatActivity {
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Fruits();
}
public void Fruits() {
textView= findViewById(R.id.pa);
String[] fruit = {"orange", "apple", "pear", "bannana", "strawberry", "mango","grape","lemon"};
Random numberGenerator = new Random();
/* Generate A Random Number */
int nextRandom = numberGenerator.nextInt(fruit.length)
;
Set<Integer> validate = new HashSet<>();
/* Add First Randomly Genrated Number To Set */
validate.add(nextRandom);
for (int i = 0; i < fruit.length; i++) {
/* Generate Randoms Till You Find A Unique Random Number */
while(validate.contains(nextRandom)) {
nextRandom = numberGenerator.nextInt(fruit.length);
}
/* Add Newly Found Random Number To Validate */
validate.add(nextRandom);
System.out.println(fruit[nextRandom]);
textView.setText(fruit[nextRandom]);
}
}
}
layout
<TextView
android:id="#+id/pa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Your while loop is an infinite loop as the validate set would contains all 8 values at one point and will always be true. Because of which your textView is never set and keep on setting again and again.
add an additional check for size of set in while loop :
for (int i = 0; i < fruit.length; i++) {
/* Generate Randoms Till You Find A Unique Random Number */
while(validate.size() != fruit.length && validate.contains(nextRandom)) {
nextRandom = numberGenerator.nextInt(fruit.length);
}
/* Add Newly Found Random Number To Validate */
validate.add(nextRandom);
Log.i("HELLO",fruit[nextRandom]);
textView.setText(fruit[nextRandom]);
}
The above will print the randomly picked fruit and will skip once validate is full.
Note : I have added an additional check of set size(just as an example), you can add your breakpoint on which you have to be out of the loop.
The while loop will repeat forever.
When i equal fruit.length-1, validate has stored numbers in range [0,fruit.length), it led the condition in the while loop always true, and program can not get out the loop cause nextNumber you generated inside the while loop always in range [0,fruit.length). For simpler, let imagine the fruit array has only one element.
I have a UI with some EditTexts in it and this set of edittexts can repeat number of times (not too much but 3 - 10 times max) based on the number of items in the list.
User can edit/modify/delete the item or edit the value of the edit texts. Currently I am doing this manually with "AddView/RemoveView", manually handling the states etc, however it is a lot of work as I have many scenarios like this.
We have a web app with the very same functionalities and we are using AngularJS to deal with all these, which, as you know is amazingly easy.
is there any closer way to bind the axml/xml view with a collection (may be an Observable collection and at least from the code behind) that will take care of collection changes as well as the individual field changes without me doing all this manually. In some scenarios I have to display images as well.
Also, I tried using a ListView, however it doesn't work as I would expect it to work.
is there any closer way to bind the axml/xml view with a collection (may be an Observable collection and at least from the code behind) that will take care of collection changes as well as the individual field changes without me doing all this manually.
The answer is no, there isn't. Android's views have to be bound to certain context/activity when they are created. They can't be isolated, so add/remove the EditTexts have to be implemented by yourself.
Currently, the closest way to your requirement is to create an ObservableCollection and listen for the CollectionChanged event and when CollectionChanged add/remove the view in your container:
[Activity(Label = "Demo", MainLauncher = true)]
public class MainActivity : Activity
{
Button btnAdd;
ObservableCollection<View> oc;
LinearLayout container;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
btnAdd = FindViewById<Button>(Resource.Id.btnAdd);
btnAdd.Click += BtnAdd_Click;
GenerateET(Resource.Id.container, this, 3);
}
private void BtnAdd_Click(object sender, System.EventArgs e)
{
EditText et = new EditText(this);
et.Text = "test";
et.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
oc.Add(et);
}
public void GenerateET(int resId, Activity activity,int num)
{
//create an observable collection
oc = new ObservableCollection<View>();
container = activity.FindViewById<LinearLayout>(resId);
for (int i = 0; i < num; i++)
{
EditText et = new EditText(activity);
et.Text = "test";
et.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
container.AddView(et);
oc.Add(et);
}
oc.CollectionChanged += Oc_CollectionChanged;
}
private void Oc_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
for (int i = 0; i < e.NewItems.Count; i++)
{
//add the view manually
container.AddView((View)e.NewItems[i]);
}
}
}
}
Main.axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
<Button
android:id="#+id/btnAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add EditText"/>
</LinearLayout>
Edit: I have been able to track the problem down to the use of EditText rather than TextView. The repeated calls only happen when a field is an EditText and the system behaves itself when the field is a TextView. I can find nothing in the documentation or online that indicates that LineBackgroundSpan will not work with EditText.
I have updated the MCVE to show how things work with TextView (it does) and with EditText (it doesn't - at least not well). My updated question is how to get LineBackgroundSpan working with EditText.
I have implemented a simple class to add a rounded background to text in an EditText using LineBackgroundSpan. Everything works OK but while debugging I noticed that the drawBackground method of my class is called repeatedly and, seemingly, without end for each span in the string even though no changes are being made. It is not apparent on the display, but is readily apparent if a breakpoint is set in the drawBackground method.
In trying to track down the issue, I was able to reduce the code down to an MCVE.The following code will simply highlight an entire line of text. The top line is an EditText and the bottom line is a TextView. (This is not what I am really trying to do, but it serves the purpose.)
This MCVE exhibits the problem for me on emulators running API 17 and API 24 as well as an actual phone running API 24. Setting the disableDraw argument to true for the constructor of RoundedBackgroudSpan() will disable background drawing action in drawBackground(). I am seeing the problem on the EditText even with background drawing disabled.
What is going on here? Am I misunderstanding how to work with spans? Will spans not work with EditText? Any help will be greatly appreciated.
MainActivity.java
package com.example.bgspanmcve;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.SpannableString;
import android.text.style.LineBackgroundSpan;
import android.util.Log;
import android.widget.EditText;
import android.widget.TextView;
import static android.text.Spanned.SPAN_INCLUSIVE_INCLUSIVE;
public class MainActivity extends AppCompatActivity {
final String dispString = "XAB CD EF";
private static int count = 0; // times drawBackground is called
#Override
protected void onCreate(Bundle savedInstanceState) {
EditText editText;
TextView textView;
RoundedBackgroundSpan bg;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up the EditText field with a span.
// RoundedBackgroundSpan#drawBackground will be called forever for this EditText.
editText = ((EditText) findViewById(R.id.editText));
SpannableString ssEditText = new SpannableString(dispString);
bg = new RoundedBackgroundSpan(INHIBIT_DRAWING, false);
ssEditText.setSpan(bg, 0, ssEditText.length(), SPAN_INCLUSIVE_INCLUSIVE);
editText.setText(ssEditText);
// Set up the TextView field with a span.
// RoundedBackgroundSpan#drawBackground will be called once for this TextView.
textView = ((TextView) findViewById(R.id.textView));
SpannableString ssTextView = new SpannableString(dispString);
bg = new RoundedBackgroundSpan(INHIBIT_DRAWING, true);
ssTextView.setSpan(bg, 0, ssTextView.length(), SPAN_INCLUSIVE_INCLUSIVE);
textView.setText(ssTextView, TextView.BufferType.EDITABLE);
}
private static class RoundedBackgroundSpan implements LineBackgroundSpan {
private boolean mDisableDraw;
private boolean mIsTextView;
RoundedBackgroundSpan(boolean disableDraw, boolean isTextView) {
super();
mDisableDraw = disableDraw;
mIsTextView = isTextView;
}
#Override
public void drawBackground(
Canvas canvas, Paint paint, int left, int right, int top,
int baseline, int bottom, CharSequence text, int start, int end, int lnum) {
count++;
if (mIsTextView) {
Log.d(TAG, "<<<<drawBackground (TextView) #" + count);
} else {
Log.d(TAG, "<<<<drawBackground (EditText) #" + count);
}
if (mDisableDraw) return;
Paint localPaint = new Paint();
RectF rect = new RectF(left, top, right, bottom);
localPaint.setColor(BG_COLOR);
canvas.drawRoundRect(rect, RADIUS_X, RADIUS_Y, localPaint);
}
private final String TAG = RoundedBackgroundSpan.class.getSimpleName();
private final int BG_COLOR = 0xfF00FF00;
private final int RADIUS_X = 20;
private final int RADIUS_Y = 20;
}
private final static String TAG = MainActivity.class.getSimpleName();
private final boolean INHIBIT_DRAWING = true;
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context="com.example.bgspanmcve.MainActivity">
<EditText
android:id="#+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="0dp"
android:inputType="text"
android:paddingEnd="0dp"
android:paddingStart="0dp"
android:text="EditText"
android:textSize="20sp" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#id/editText"
android:layout_below="#id/editText"
android:layout_marginStart="0dp"
android:layout_marginTop="16dp"
android:paddingEnd="0dp"
android:paddingStart="0dp"
android:text="TextView"
android:textSize="20sp"
android:textStyle="bold" />
</RelativeLayout>
The call to drawBackground() is timed to the rate of the flashing cursor which is about 500 ms as suggested by #Suragch. I am now convinced that the call to drawBackground() is made as part of the cursor implementation.
As a quick, but not definitive test, I have set the EditText field to not show the cursor but to still be editable (android:cursorVisible="false"). When this attribute set to false, the repeated calls to drawBackground() cease.
I need help understanding how to accomplish math between different EditText views. I am not asking someone to write me the code but maybe explain what is involved to get this done.
I wanted to post a picture of this but as a new user I can not. Basicly I have a EditText for the following: Width, Length, Eave Height, Pitch.
I have ID's for all the TextViews I just dont know how to program the behind the scenes math involved to make them work. I do have the equations needed to perform the math just not sure where and how to put them in java.
Basicly I need the user to enter a number in each of the top 4 boxes. I need to use an equation to generate the answer that will be displayed in the "SQFT" box. The user will also input a number in a cost box which will generat a "Total" that needs to be displayed in a separate TextView.
Any help would be appreciated, even if it is to point me in a direction of a tutorial to get me started. Thanks for your help.
Just to show what type of math I need to use, below is the equation I use for excel to calulate.
(length+width)*(Eave+1)*2 + (((width/2)/12*Pitch)*(width/2)*2)
I'm not sure if you don't know how to extract the numbers entered in the EditTexts, how to actually do the math calculation, how to let the user initiate the calculate or how to present it.
I created a small demo that has 2 EditTexts, and a TextView that displays the sum of the numbers entered. The user does not need to press any buttons to perform the calculation, it is performed automatically every time the user updates the text (I assumed this is what you wanted).
Please note this code is not good code, it uses lots of internal anonymous classes etc but it supposed to demonstrate the mechanics of how to do this.
This is the main.xml layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<EditText
android:id="#+id/a"
android:hint="input a"
android:inputType="number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:minWidth="60dp"/>
<EditText
android:id="#+id/b"
android:hint="input b"
android:inputType="number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:minWidth="60dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="a+b = " />
<TextView
android:id="#+id/total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp" />
</LinearLayout>
And this is the sample Activity:
package com.example;
import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.EditText;
import android.widget.TextView;
public class SumActivity extends Activity
{
private int a;
private int b;
private TextView totalOutput;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
EditText inputA = (EditText) findViewById(R.id.a);
EditText inputB = (EditText) findViewById(R.id.b);
totalOutput = (TextView) findViewById(R.id.total);
inputA.addTextChangedListener(new TextChangedListener()
{
#Override
public void numberEntered(int number)
{
a = number;
updateTotal();
}
});
inputB.addTextChangedListener(new TextChangedListener()
{
#Override
public void numberEntered(int number)
{
b = number;
updateTotal();
}
});
}
private void updateTotal()
{
int total = a + b; // This is where you apply your function
totalOutput.setText("" + total); // need to do that otherwise int will
// be treated as res id.
}
private abstract class TextChangedListener implements TextWatcher
{
public abstract void numberEntered(int number);
#Override
public void afterTextChanged(Editable s)
{
String text = s.toString();
try
{
int parsedInt = Integer.parseInt(text);
numberEntered(parsedInt);
} catch (NumberFormatException e)
{
Log.w(getPackageName(), "Could not parse '" + text + "' as a number", e);
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
}
}