Any one please guide me,
How to create a custom component in xml and java file
pass attributes from xml (this i somewhat completed)
how to pass attributes dynamically from new customClass() -- constructor method. -- i dont know how to implement this point
for Eg : I created a custom component with two textview as a single component. In xml i created two component by xml attributes. Now i want to create two new component by java code
by calling the constructor of my customClass.java I dont know how to create a new component dynamically from java code and how to display that in a view(Say a relative layout) Please help me provide any link or blog.
I have spent 1 week for this, But i didnt get any solution please help me
its very simple:
in your layout xml file simply put the following lines of xml code:
<com.example.project.MyComponent
android:id="#+id/myid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
Now, write a class named as your component:
public class MyComponent extends RelativeLayout {
public MyComponent(Context context, AttributeSet attr) {
super(context,attr);
}
#Override
public void onFinishInflate() {
// this is the right point to do some things with View objects,
// as example childs of THIS View object
}
}
Remember the constructor: this constructor is needed by the LayoutInflater to
find your component. And, dont forget to call super(...) when required.
You can do this by calling the constructor with context in its parameter and then setting the attributes with getter setters. You can find a good tutorial at Android tech point
MyComponent mycomponent = new MyComponent(context);
myComponent.setFirstTextView("text1");
myComponent.setSecondTextView("text2");
And then finally
layout.addView(myComponent);
Related
How can I passs multiple strings into custom views constructor in android
public DrawSomethingView(Context context, String originalBgPath, String pattern) {}
and why it forces to do it like that ?
public DrawSomethingView(Context context, AttributeSet S){
You need the standard constructors so the framework knows how to inflate them, e.g. from an XML layout. If you put a DrawSomethingView in your layout, how would it know what to pass for originalBgPath etc? You also need a Context and AttributeSet at a minimum to call one of the View superclass's constructors. You can read more about it here
That link also tells you how to create your own attributes, that you can add to the XML for your custom view, and pull out the data in the class itself. So you could add your strings as part of the XML definition. If you want to set them programmatically instead, you'll need to add some properties you can set (which you could also set when you read those attributes).
But there's no way to force them to be set, since you can't create your own version of the constructor that requires them (and the framework wouldn't have values to provide anyway). So you'll need to handle the possibility they're missing (e.g. nullable properties, default values), and maybe write a builder function that you can call from your code, that does require those values and creates and sets up the custom view before passing it back to you.
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
I'm trying to implement updated solution by Pedram from this answer, but I don't know to create a new instance of CircleProgressBar. It requires AttributeSet to be passed as a parameter, but how to get it?
CircleProgressBar circleProgressBar = new CircleProgressBar(MainActivity.this, ?);
The AttributeSet constructor is used when a view is inflated through a layout defined in XML. If you're constructing one in code, you should use the single argument constructor (e.g. new CircleProgressBar(MainActivity.this)). If the single-argument constructor is not defined, you just need to add it. You'll just need to add some getters/setters for the properties if you want to be able to construct it entirely from within Java code.
Alternately, just define a layout XML (example name view_progress_circle.xml) with a single item:
<com.your.packagename.CircleProgressBar
android:layout_width="100dp"
android:layout_height="100dp"
// etc. add other attributes here
/>
Then in code, create it with:
CircleProgressBar bar = (CircleProgressBar) LayoutInflater.from(MainActivity.this)
.inflate(R.layout.view_progress_circle, parent, false):
where parent is the ViewGroup you're going to attach the view to.
As a beginning Android programmer who is not a beginning programmer, I am alarmed by the amount of time it took me until I realized that the crash was resulting from omitting to use the constructor taking AttributeSet as a second parameter and writing instead the following code for a custom view defined in an XML layout.
////////MyView.java////////
public class MyView extends View {
public SimpleView(Context context) {
super(context);
}
...
}
My question is this: What could I have done (in Eclipse, the ADT variant) to be able to determine this error quickly? I look rather carefully at lint messages and was hoping that that habit would spare me spending hours for a single error.
The manual does of course clearly state that custom views defined in an XML layout should use the (Context, AttributeSet) variant of the View constructor, but it is hopeless to program at any level while recalling with precision every last detail in the reference pages.
There should be the following error in the Graphical Layout:
Custom view MyView is not using the 2- or 3-argument View
constructors; XML attributes will not work
But I agree that a compile-time error would be better...
I am new to android .can any one solve the following problem?
I just create the class like below .I need to know how to set property for the Edit text field
public class CustomEditText extends EditText{
public CustomEditText(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
}
Note: I mean the property like this
Edittext.setText("Demo");
Thanks in advance.
You need to create member variable and methods inside your CustomEditText.
Once you have them you can access it.
So there are a couple ways this can be interpreted and I will try to cover all of them.
EditText has multiple constructors. The one you have overridden requires that you as the developer set the properties in code for the rest of this instances usage. So you can actually just call setText(someString) from within this class or since the method is public call it directly on an instance of your class.
If you override the constructor that contains an attributeSet,
EditText(Context, AttributeSet)
You can use your component as part of an xml layout and set attributes on it there as if it were another EditText (as long as you call super(context, attributeSet). If you want to define your own custom attributes on top of that then that's actually quite neat how you do this.
In your project hierarchy, from the root you should either have or need to create a folder called "res/values" Within that folder a file named attr.xml should be created.
<declare-styleable name="myCustomComponents">
<!-- Our Custom variable, optionally we can specify that it is of integer type -->
<attr name="myCustomAttribute" format="integer"/>
...
<!-- as many as you want -->
</declare-styleable>
Now within your new constructor that makes use of the AttributeSet, you can read this new attribute, "myCustomAttribute".
public CustomEditText(Context context, AttributeSet set) {
super(context, set);
// This parses the attributeSet and filters out to the stuff we care about
TypedArray typedArray = context.obtainStyledAttributes(R.stylable.myCustomComponents);
// Now we read let's say an int into our custom member variable.
int attr = typedArray.getInt(R.styleable.myCustomComponents_myCustomAttribute, 0);
// Make a public mutator so that others can set this attribute programatically
setCustomAttribute(attr);
// Remember to recycle the TypedArray (saved memory)
typedArray.recycle();
}
Now that we have declared our new attribute and have setup code to read it, we can actually use it programatically or in an XML layout. So let's say you have an Xml layout in file, layout.xml
<ViewGroup
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.my.apk.package"
>
...
<com.my.full.apk.package.CustomEditText
android:id="#+id/custom_edit"
...
custom:myCustomAttribute="12"
/>
...
</ViewGroup>
So in this we create a layout like normal, but notice we declare a new xml namespace. This is for your new component and your apk. So in this case "custom" is being used it will look inside your defined stylables for new parameters. By doing the previous steps with attr.xml, you have declared "myCustomAttribute" as a component attribute off of the http://schemas.android.com/apk/res/com.my.apk.package namespace. After that it's up to you to decide what attributes you would like to expose and what those attributes actually mean. Hope that helps.