I'm makeing a project that can show defferent watches to users.The watch has different clock dial.I want to make two different widgets(the watch)in one screen and the watch has different time and clock dial.How can I do it?
You can make your own control and then include that control twice in a single screen.
package com.sample.ui.control;
public class MyControl extends LinearLayout {
public MyControlContext context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.control_my_control, this);
}
}
You can add extra code as necessary. The xml file control_my_control is the XML for your watch. In that XML, be sure the outer element is a element.
For the view that will contain two of these, you use them like:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<com.sample.ui.control.MyControl android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="#+id/control1" />
<com.sample.ui.control.MyControl android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="#+id/control2" />
</LinearLayout>
Related
Does anybody know a tool to create java code from a xml layout file.
It would be useful, to create quickly a custom view (I do not want to create a separate library project) that I would like to include in an activities layout.
So lets say my custom view would be a Relative Layout with some child views.
It would be great if the tool could generate from a layout file like this:
<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">
<!-- some child Views -->
</RelativeLayout>
a java class like this:
class CustomView extends RelativeLayout{
/*
* Generate all the Layout Params and child Views for me
*/
}
And at the end I could use this generated class in a normal XML
<LinearLayout
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"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
text="Hello World" />
<com.example.CustomView
android:layout_width="match_parent"
android:layout_height="100dp"
/>
</LinearLayout>
Does such a tool exists?
It would be useful, to create quickly a custom view (I do not want to
create a separate library project) that I would like to include in an
activities layout.
You can already do it. Create a custom view class and inflate custom layout there.
package com.example.view;
class CustomView extends LinearLayout {
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater.from(context).inflate(R.layout.custom_view, this, true);
}
}
Create a layout for that custom view class using <merge> tag as the root. Android will add content of tag into your custom view class, which is, in fact, LinearLayout in our case.
// custom_view.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android"
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
text="Hello World" />
</merge>
You are done. Now you can add this custom class to your layout.
<com.example.view.CustomView
android:id="#id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
/>
No because there's 2 better ways to do it.
1)Use an <include> tag. That allows you to include a 2nd xml file.
2)Use a custom class, but have it inflate the second xml in its constructor. That way you can keep the layout in xml for the class.
Typically I use 2 if I want to create custom functionality where you set/change multiple values at one time, and 1 if I just want to break up my xml file into chunks.
In my project I have screens where the same pattern is repeated a lot - it's basically a container for views consisting of a linear layout with the heading, image and specific background. To avoid copying and pasting the same sequence multiple times I thought I could create a compound view, extend LinearLayout and define all the "styling" there, and then just use that component in my layouts.
I followed howto's and examples and got my compound view to work. However, all examples I've seen use the resulting view as follows:
<com.myproject.compound.myview
...some attrs...
/>
I.e. no children are added via XML. I need to use it like this:
<com.myproject.compound.myview
...some attrs...>
<TextView
..../>
...other views...
</com.myproject.compound.myview>
Since I'm extending LinearLayout I was expecting "myview" tag to work like LinearLayout too, but for some reason items I put inside do not get drawn. Is there something I need to do specially to get the inner views to draw?
My extended LinearLayout is very simple, I am not overriding any methods and just calling super in constructor and inflating the layout like this:
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_compound_view, this, true);
UPDATE: I thought I'd add an XML as a point of reference:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#drawable/bg"
android:padding="12dp">
<TextView
android:id="#+id/section_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FF0000AA" />
<ImageView
android:layout_width="match_parent"
android:layout_height="2dp"
android:src="#drawable/line" />
</LinearLayout>
Actually found a more elegant solution. Just need to use merge tag instead of LinearLayout in the compound view. All boils down to:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
<TextView
android:id="#+id/section_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="HEADING"
android:textColor="#FF0000AA" />
<ImageView
android:layout_width="match_parent"
android:layout_height="2dp"
android:src="#drawable/line" />
</merge>
and
public class CompoundLayout extends LinearLayout{
public CompoundLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.compound_layout, this, true);
}
}
Main layout:
<com.testbench.CompoundLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFDDEE"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Inner text"
android:layout_gravity="center_horizontal"/>
</com.testbench.CompoundLayout>
After reading through the Android source and examples I think I figured this one out. Basically in my case it's a hybrid of Compound View and Custom Layout. "Compound view" part takes care about laying out and drawing the content of the XML which specifies the "container". But items inside that container get inflated later on and in my implementation they didn't get laid out.
One way is to follow the Custom Layout path - I'd have to implement onLayout() and onMeasure() to properly calculate my children (and I did during my research, it worked). But since I really do not need anything different than what LinearLayout does already and I don't want to copy/paste it's code (those methods are huge there), I just decided to override the method onFinishInflate() and added my "container view" there. Here is the whole code, please comment is something can be improved.
public class CompoundLayout extends LinearLayout{
View mView;
public CompoundLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = inflater.inflate(R.layout.compound_layout, this, false);
}
#Override
public void onFinishInflate(){
super.onFinishInflate();
addView(mView, 0);
}
}
Then in Activity's main layout I just use my custom layout the same way I would use LinearLayout. It renders the same, but always with those TextView and ImageView on top.
According to this CommonsWare example I managed to get my RelativeLayout subclass to be merged with my layout described in a xml layout with merge root. My only concern is that I cannot describe my RelativeLayout parameters in xml.
My xml layout:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:my="http://schemas.android.com/apk/res/hu.someproject"
android:layout_width="36dp"
android:layout_height="wrap_content"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:width="36dp" >
<RelativeLayout
android:id="#+id/upper_container"
style="?pretty_style"
android:layout_alignLeft="#+id/image_title"
android:layout_alignParentTop="true"
android:layout_alignRight="#+id/image_title"
android:layout_centerHorizontal="true" >
<View
android:id="#+id/upper_indicator"
android:layout_width="fill_parent"
android:layout_height="5dp"
android:layout_alignParentTop="true"
android:background="#color/mycolor" />
<TextView
android:id="#+id/text_degree"
style="?pretty_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="23°" />
</RelativeLayout>
<hu.MyView
android:id="#+id/image_title"
style="?my_image_title"
android:layout_below="#+id/upper_container"
android:layout_centerHorizontal="true"
my:myColor="#2f8741"/>
I think the problem is that merge happens to the children of the merge tag, and not the merge itself. Any idea how can I get my parameters in the merge to affect my RelativeLayout?
My RelativeLayout subclass, without package declaration and imports:
public class MyRelativeLayoutSubclass extends RelativeLayout {
public MyRelativeLayoutSubclass(Context context) {
super(context);
initTile(null);
}
public MyRelativeLayoutSubclass(Context context, AttributeSet attrs) {
super(context, attrs);
initTile(attrs);
}
public MyRelativeLayoutSubclass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initTile(attrs);
}
private void initTile(Object object) {
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_great_little_layout, this, true);
}
}
I know I can add everything to a LayoutParams, and then add my MyRelativeLayoutSubclass with that LayoutParams, but I would like escape that, that's a lot of unnecessary code.
I think the problem is that merge happens to the children of the merge tag, and not the merge itself.
AFAIK, you are correct. <merge> is a placeholder, not a ViewGroup.
I know I can add everything to a LayoutParams, and then add my MyRelativeLayoutSubclass with that LayoutParams, but I would like escape that, that's a lot of unnecessary code.
Create an XML layout file containing a MyRelativeLayoutSubclass element, and put your attributes there. Then, inflate that layout.
Extracting all the attributes into Style was a solution for me. As a bonus it's screen-size dependent unlike the hard-coded attributes or Java-code. Maybe you can go further and put it into the Theme attributes.
<com.example.widget.MyCustomView
android:id="#+id/my_custom_view"
style="#style/MyCustomView.Default"/>
I have a custom made UI component which have inside another custom made UI component (which is separated for convenience purposes).
I want to be able to pass my own attributes to the father component, and read them inside the sub-component. In that way, the only thing the developer has to see is the father component, w/o needing to know there's another component inside.
For instance, this is the application's main layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:udinic="http://schemas.android.com/apk/res/com.udinic"
android:id="#+id/main"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<com.udinic.FatherComponent android:id="#+id/fatherComp"
android:layout_width="fill_parent"
udinic:itemNum="9"
android:layout_height="wrap_content" />
</LinearLayout>
and the father component's xml looks like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:udinic="http://schemas.android.com/apk/res/com.udinic"
android:id="#+id/fatherLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<com.udinic.SubComponent android:id="#+id/subComp"
android:layout_width="fill_parent"
udinic:itemNum=<<Get the itemNum passed to me>>
android:layout_height="wrap_content" />
</LinearLayout>
I didn't find any way to do this using the XMLs only. Does anyone knows anything that can help solving this?
Thanks
You'll need to use the constructor of your father class to pass the value into the sub class.
public FatherClass(Context context, AttributeSet attrs)
{
super(context, attrs, LAYOUT);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomLayout);
//for string attribute
textView.setText(getStringAttribute(typedArray, R.styleable.CustomLayout_labelText));
//for resources
int textAppearance = typedArray.getResourceId(R.styleable.CustomLayout_textAppearance, -1);
textView.setTextAppearance(context, textAppearance);
//for integers
int inputType = typedArray.getInt(R.styleable.CustomLayout_inputType, -1);
editText.setInputType(inputType);
}
I have made a Custom Component in XML, consisting of a button with an imageview stacked on top of it:
<myapp.widget.ClearableCaptionedButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="#+id/ccbutton_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|left"
android:textAppearance="?android:attr/textAppearanceMedium"
android:background="#android:drawable/edit_text"/>
<ImageView
android:id="#+id/ccbutton_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dip"
android:layout_alignRight="#id/ccbutton_button"
android:layout_alignTop="#id/ccbutton_button"
android:layout_alignBottom="#id/ccbutton_button"/>
</myapp.widget.ClearableCaptionedButton>
extract of java source code:
public class ClearableCaptionedButton extends RelativeLayout implements OnClickListener {
...
public ClearableCaptionedButton(Context context, AttributeSet attrs) {
super(context, attrs);
// some stuff that works fine
}
..
protected void onFinishInflate() {
super.onFinishInflate();
mButton = (Button) findViewById(R.id.ccbutton_button);
mClear = (ImageView) findViewById(R.id.ccbutton_clear);
mButton.setText(""); // error here: mButton == null
}
My problem is similar to this one. When i try to find the views inside the custom compound, findViewById returns null. But, as you can see, i already added super(context, attrs); to the constructor.
i am using the custom component directly in xml layout, like this:
<LinearLayout>
<!-- some stuff -->
<myapp.widget.ClearableCaptionedButton
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:caption="to"/>
</LinearLayout>
can anybody spot something? thanks.
I am confused by your two XML layouts.
The second one is where you say you use the widget. Hence, I am assuming that the class named ClearableCaptionedButton is in the package de.pockettaxi.widget.
I am further assuming that the Button and ImageView shown in your first layout are things that are always supposed to be in ClearableCaptionButton, not something supplied by the reuser of ClearableCaptionButton.
If those assumptions are all correct, then you have two problems.
First, you aren't using the first
layout anywhere that I can see.
Second, the first
layout has reference to a myapp.widget.ClearableCaptionedButton that probably does not exist.
I would replace the myapp.widget.ClearableCaptionedButton element with a <merge> element, then inflate that layout in the constructor or onFinishInflate() of ClearableCaptionedButton.
Here is a sample project from one of my books that shows the use of a custom widget that works in this manner.
Also, given your package name, I hope that it is either a very large pocket or a very small taxi... :-)