Is there a view in android, that can store one object and display the object's toString() return value like a TextView?
Or do I have to mimic the behaviour in taking a ListView and ensure that only one item is in its adapter?
I need this, because I use drag & drop to move objects around and I need a view, that can display and store one of the objects.
Thank you!
There is no such view. Depending on your requirements, you have to implement this functionality.
yes, there is such a view and you already mentioned it. it's called TextView, and you'd use it like this,
TextView tv = (TextView)findObjectById(R.id.tv);
tv.setText(myObject.toString());
if you don't like like that, extend TextView like this,
class ToStringView extends TextView {
...
public void setObject(Object o) { setText(o.toString()); }
}
Related
Let's say I have a layout like this:
Creating the layout is not complicated, if the questions are fixed. But my requirement is to display the questions from database, like this:
As you can see, there are 4 sectionIds. That means we have 4 categories. I'm thinking to use LinearLayout for this. Then for each categories, we have different amount of questions. If the question type is R, use RatingBar. But if the type is D, then use TextArea. I also plan to use LinearLayout for each questions. Now the challenge is creating those layout dynamically, which I think is not that easy. What's the least complicated way to do this?
I have had to do this in several opportunities, so I wish I can give a tip or more:
If your problem is not complex, look for something that has already solved it:
This library create a layout based on Firebase data
This library is for creating forms
Most of the times, any library will work because programmatic views are tight to specific requirements, so you will have to go on your own.
Customized Solution
Creating programmatic views it has a skew learning curve but with time you will be able to solve it.
Defining your fields:
Create fields or partial package and put those classes inside. You want to create a class for each type of field so you can reuse easily and modify it is done in that class.
Also, define what is common for every field. You can do this with an interface:
interface FormField {
String result();
boolean isValid();
void setError();
}
In this case, this interface will allow you to handle the result of the field, know if it is valid and set the errors. Validations should be inner once are requested, and error should be settable do internal validations and from outside.
The result you are getting can change by specific methods in other classes but having a common String is most of the time useful even for showing a summary to the user.
There is another benefit, you can create a list of your fields by your interface, every fields implement it:
List<FormFields> fields = new ArrayList();
//fields.add(ANY CLASS THAT IMPLEMENTS THE INTERFACE);
Creating a Field
Start by creating a class that extends a suitable view for your field:
public class InputText extends EditText implements FormFiel {
//You can simply add customizations in the constructor
}
public class InputText extends LinearLayout implements FormField {
//Maybe you need an input with a label, hence a TextView and an EditText will go inside of this
}
The rule of thumb for this task about constructor is one param for java two params for xml. So wherever you need to put the view, you use either one of those.
Handling Field appearance
If you need something simple maybe just set everything in the constructor.
public class InputText extends EditText implements FormField {
//You can simply add customizations in the constructor
public InputText(Context context) {
super(context)
setLayoutParams(new LayoutParams(LayoutParams.WrapContent...)
}
}
if you need something more complex use the layout inflater.
public class InputText extends LinearLayout implements FormField {
//You can simply add customizations in the constructor
public InputText(Context context) {
super(context)
LayoutInflater layoutInflater = LayoutInflater.from(getContext())
//You have to create the layout, a neat trick is create it inside a linear layout eand then use refactor/extract
//The last boolean in the method attach it to the view
layoutInflater.inflate(R.layout.field_input_text, this, true;)
//Maybe you want to find something, this could be a field variable
TexteView tv = this.findViewbyId(R.id.inside_the_inflated_layout)
}
}
Define a model
You need to define a model for all the field types
public class FireField {
private String label, hint, type;
// Empty constructor and getters and setters
}
Create a Container class
The container class probably is a linear layout with orientation vertical, you want to create it anyway and added in the xml (remember 2 params constructor) so you can add inside that view a way to get all your fields, a special method for that.
It can be a list of fields, it can be the list of the data you need to send.
This way, fiedls take care of their own logic and form take care of the general logic.
Add the views
You have to fetch your data then do a loop and for each type of the data, add a new view, this is when the List<FormField> of views come in handy, following is pseudo code
List<FireField> data = new ArrayList();
//You can also have String, View map here, where the key is the type and the value View is your field
List<FormField> fields = new ArrayList();
for (DataSnapshot children: snapshot.getChildren()) {
FireField field = children.getValue(FireField.class);
data.add(field);
if (field.getType.equals("INPUT_TEXT)) {
//Here Im addinf the field in the constructor, then the view should take care of it
new InputText(context, field)
//Here I'm initializing the view, the view inside that method should set labels and other
InputText input = new InputText(this);
input.initialize(field);
fields.add(input);
//You can add it here or in other place re using some of the lists above
container.addView(input);
}
}
Finally use any of the list and the container method to get the data and send it to Firebase
My android is very rusty, so this is the best way I can explain this:
A card contains an image, a value, and a URL
I have an array of values, a parallel array of images, and of URLs (values[i] <-> images[i] <-> URLs[i])
Have a GridView that I want to use to display many of these cards
The problem:
I have a class that extends BaseAdapter to create a custom view to display the three elements of the card
Using the getView method of said adapter, I use the "i" expected by getView as a mental index of which card we are talking about.
Unfortunately I realized that i=0 means the currently visible first card, I thought it meant the overall first card. This makes it useless as a system to keep track of the overall position of cards.
So, the visible elements are populated correctly in the view. But, if I scroll down and then back up, some internal elements have been jumbled up. So clicking a card might now lead to the URL of a card that was initialized after it.
What I need help with:
A better way to index or populate each card's content that will be permanent.
I am wildly confident I am doing this in a horrendous way. I'm imagining there must be some way to say that:
When GridView is created -> populate each card's details and fill in GridView.
Current Main Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_list);
gv = (GridView) findViewById(R.id.cardGridView);
gv.setAdapter(new CardView(this, cardURLs, cardNames, cardPrices, cardImages));
}
Current CardView Activity:
public CardView(CardListActivity mainActivity, String[] cardURLs, String[] cardNames, Double[] cardPrices, int[] cardImages){
//...
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public class Holder{
TextView priceTV;
ImageView cardIV;
String cardName;
}
#Override
public View getView(final int i, View convertView, ViewGroup parent) {
//...
View rowView;
rowView = inflater.inflate(R.layout.card_item_view, null);
//HERE IS WHERE I SET THE PRICE AND IMAGE USING i
holder.priceTV.setText("$" + prices[i].toString());
holder.cardIV.setImageResource(images[i]);
//...
return rowView;
}
Turns out the problem was something else.
The actual problem ended up being caused by these Dialogs I would create to verify if the user wanted to open the website.
I was creating them inside getView, all in the same variable, which meant that the last elelemnt to get initialized would be the one used in the dialog.
I fixed this by moving the dialog creation into the onClick for the view.
Firstly, You should wrap your contents into objects so that each CardContent object contains a url, an image and a value, Then pass those into your adapter. That will be much easier on you, you only need to maintain 1 List of CardContent rather than 3 individual lists and hoping the order doesn't get messed up.
Secondly, This sounds like a case for a Recyclerview. You can use a GridLayoutManager with a Recyclerview instead of a GridView so that your views get recycled and you have less overhead. Luckily the code is largely the same.
See https://developer.android.com/training/material/lists-cards.html for pretty much what you want.
I am new at android programming and want to create an application in which I can add multiple custom tags to an displayed Image. I researched a bit and found out aboutsetTag() method of ImageView. But it does mention if it allows multiple tagging.
Also is there any way that those tags to remain visible (along with appropriate tagged position) on the image?
Will I require an SurfaceView or GridView for this?
Sources :
Android Image View
android-Image View set Tag
Thank you.
Instead of looking for multiple tags you can use a class MyTag as follows to tag more than one data to a view
public class MyTag
{
int int_Tag;
String string_Tag;
MyClass myclass_obj_Tag;
public MyTag()
{
int_Tag=0;
string_Tag=null;
myclass_obj_Tag=null;
}
public MyTag(int i,String s,MyClass m)
{
int_Tag=i;
string_Tag=s;
myclass_obj_Tag=m;
}
}
create an object of this class and assign values to variables in object
MyTag myTag=new MyTag(1,"string_tag",myClass_obj);
iv.setTag(myTag);
just give it a try,I have used this method,
You can add any object as a tag. If the data you're adding need more data, the simplest way would be to add a Hashtable as the tag. Then add all the key/value pairs you want to that Hashtable.
I have seen related answers and I do not know ehich one is the appropriate for me.
I have a listView and each row has a textview. I want given some conditions, each row to get different color.(Imagine that I am getting data from a DB, and given the value I get, i want text set to different color) My code is shown below:
public class TrailsConditionScreen extends ListActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
seeTrails();
}
private void seeTrails() {
String[] help=new String[] {"foo","bar"};
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,R.layout.row,R.id.text1,help);
setListAdapter(adapter);
}
}
This code so far just prints them on the list.
Now I want when retrieving values from the db, given the value i get set a different color on each row. imagine that my codes retrieves data from a table an I want when reading the first line , given the number set the appropriate color on the first line of the listview. Then go to second lone of the db,set color for the second line of the list and so on.. i have successfully implemented the reading from the db but i do not know how to set color on specific row. In pseudo-code it looks like this.
for i=0 to number of lines in db{
read_data();
if key_value=0 then color_of_line(i)=red;
else color_of_line_i)=green;
}
Any help for this?
You must create a custom adapter to handle this instead of using the ArrayAdapter. Extend the ArrayAdapter and override the getView method. And inside the getView method based on the condition you can change the color of the text on your textView.setTextColor.
To write a custom adapter check the tutorial here (6. Tutorial: Implementing your own adapter). This example doesn't use the holder pattern but you should.
Your best bet is to extend ArrayAdapter and create your own class.
In the getView() method, execute your condition and set the color to be drawn. There are a lot of good tutorials on creating your own adapters. Check, for instance, http://www.ezzylearning.com/tutorial.aspx?tid=1763429&q=customizing-android-listview-items-with-custom-arrayadapter.
Hope it helps!
Inorder to achieve this, you will need to use a custom adapter. Since you mentioned, you are getting the data from a database, I am assuming here that you will have information in a cursor adapter. Hence, a good place to start would be to extend cursor adapter.
Within your new custom adapter, you should override getView() method. The view to be used for each item in list view is specified there. Additionally, you can also set the properties of the view there.
Depending on your business logic, you should set the text color in getView.
A tutorial here:
http://www.ezzylearning.com/tutorial.aspx?tid=1763429&q=customizing-android-listview-items-with-custom-arrayadapter
What I would do is create a CustomAdapter for the list view
public class MyCustomAdapter extends BaseAdapter
and in the funcion
public View getView(int position, View convertView, ViewGroup parent)
you have the position and you can change whatever you want.
If you search google by custom adapter listview you will get some examples
Different Color For different list item ,yes this can be achieved only if items are static only , but for dynamic content it's hard to do ...
I want to have a class "Utils", that will have several methods used all over my code. For example, I have a top bar with a textview and two ImageButtons that must display different texts and icons on different activities.
I find myself writing stuff like this on every activity:
(TextView) topBarText = (TextView) findViewById(R.id.topBarText);
topBarText.setText(R.id.mytextForThisView);
I'd like to findViewById once in my whole app, and call a method setupTopBar(String text, R.id.iconForImageButton1, R.id.iconForImageButton2), or even pass the current Activity's id and let the method figure out what to show in the text and images.
I created the class Util, but it doesn't extend Activity. The problem is that if it doesn't, findViewById isn't accessible, so I can't use it.
What's the pattern to do something like this in Android?
Your helper methods should look like
public static void setTopBarText(Activity act, int textId){
(TextView) topBarText = (TextView)act.findViewById(R.id.topBarText);
topBarText.setText(textId);
}
Then you can do a static import from Activity and call
setTopBarText(this, R.id.mytextForThisView);
The Answer is not good for some situation.
This is my method:
In your Activity:
YouCustomClassObject.passView((View)findViewById(R.id.aview));
Using parameter passing can solve this kind of problem.