custom view becomes invisible in xml layout - android

I'm creating custom view derived from EditText. My view is declared as inner class like this:
package com.woodshy.glucoXpert.DPass;
//...
public class DPassValuesEditActivity extends GenericScreenActivity {
//...
public static class DPassValuesEditField extends EditText {
protected String mDbFieldName;
public DPassValuesEditField(Context context) {
super(context);
}
public DPassValuesEditField(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.DPassValuesEditField);
CharSequence s = a
.getString(R.styleable.DPassValuesEditField_dbFieldName);
if (s != null) {
mDbFieldName = s.toString();
}
}
//...
}
}
res/attrs.xml file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="DPassValuesEditField">
<attr name="dbFieldName" format="string" />
</declare-styleable>
</resources>
I'm adding my custom view to xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.woodshy.glucoXpert"
android:id="#+id/LinearLayout01" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical">
<ScrollView android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_gravity="center_vertical"
android:scrollbars="vertical">
<RelativeLayout android:id="#+id/editFielsdLayout"
android:layout_height="fill_parent" android:layout_width="fill_parent"
android:clickable="true">
<view
class="com.woodshy.glucoXpert.DPass.DPassValuesEditActivity$DPassValuesEditField"
android:id="#+id/edtWeight" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:width="75px"
android:maxLines="1" android:layout_below="#+id/TextView01"
android:lines="1" android:gravity="center" android:imeOptions="flagNoExtractUi"
android:inputType="numberDecimal" android:maxLength="3"
app:dbFieldName="Weight"></view>
</RelativeLayout>
</ScrollView>
</LinearLayout>
but I cant see it in visual editor (Eclipse SDK, Version: 3.6.1) while it appears in application in run-time and works fine.
Am I doing something wrong? How could I get my custom view visible in visual editor?
thanks.

Had the same problem.
Looks like it (plugin) need to reload something before being able to display custom views.
Try switch target platform in Graphical Layout Editor from current to some other (for example, from 2.1 to 2.3). That helps and even after switching back to "current" (2.1 in example) it continues to display custom views.
Also sometimes it required to restart eclipse...

How could I get my custom view visible in visual editor?
You can't.

Related

How to make my own XML layout view from other views

I have one RelativeLayout that has TextView (first label) , EditText(for input), TextView (second label). I have this in at least 10 activities in my project. How I can extract view and make my own. So, if I want to change textSize , I will have to change it on just one place, not 10.
For example I would like to have this
<RelativeLayout
android:width="match_parent"
android:height="wrap_content"
>
<TextView
android:id="firstTextView"
...
android:text="I like">
<EditText
android:id="edittextColor"
hint="type some color here"
... >
<TextView
android:id="secondTextView"
...
android:text="car.">
</RelativeLayout>
So, I need something like this on a lot of place. What I would like to have is:
<MySpecialView
firstText="I like"
colorEditTextHint="type color here"
secondText="car"/>
Inflaters
Let's suppose that your RelativeLayout file is called reusable_layout. This means that you could access it as R.layout.reusable_layout (considering that you have this file stored in the layouts folder of your project).
In your usual override of onCreate() add these variables at the start: LayoutInflater inflater = getSystemService(LAYOUT_INFLATER_SERVICE);
RelativeLayout layout = inflater.inflate(R.layout.reusable_layout, null);
Afterwards, call setContentView(layout);
If you want to edit the children you can call layout.getChildAt(int childNumber); This would return you a View
An example of editing the first TextView child:
TextView tv = (TextView) layout.getChildAt(0);
tv.setText("Example String");
UPDATE:
Another way to do what you want!
Creating a custom view may do the job!
A good tutorial on these is included here: https://developer.android.com/training/custom-views/create-view.html#subclassview
I think all you need to know is included in that.
Another possibly useful source would be included here: how to add views inside a custom View?
Hope I helped,
-Daniel
You can create one common layout and include in all the 10 activities layout like this
common_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/label1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Label1"/>
<EditText
android:id="#+id/input1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/label1"
android:text="Input1"/>
</RelativeLayout>
activity_layout
<?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">
<include layout="#layout/common_layout"/>
<TextView
android:id="#+id/textinactivity_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Activity text"/>
</LinearLayout>
I hope this is what you wanted.
Although Android offers a variety of widgets to provide small and
re-usable interactive elements, you might also need to re-use larger
components that require a special layout. To efficiently re-use
complete layouts, you can use the include and merge tags to
embed another layout inside the current layout.
https://developer.android.com/training/improving-layouts/reusing-layouts.html
What about <include>
create you your_base_layout.xml and <include> it in any other xml in the place where you want to add it
your_base_layout.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/some_other_id">
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/button1" />
</LinearLayout>
<include
android:id="#+id/include_id"
layout="#layout/your_base_layout" />
example of usage: another_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/app_bg"
android:gravity="center_horizontal">
<include
android:id="#+id/include_id"
layout="#layout/your_base_layout" />
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/hello"
android:padding="10dp" />
...
</LinearLayout>
This is how you access views in it,
View includedLayout = findViewById(R.id.some_id_if_needed);
Button buttonInsideTheIncludedLayout = (Button) includedLayout.findViewById(R.id.button1); // if there is a button in your base layout that you included access like this
find great answers >here
You can define your own control with specified attributes.
Save ButtonPlus.java into your package.
e.g.
public class ButtonPlus extends Button {
public ButtonPlus(Context context) {
super(context);
}
public ButtonPlus(Context context, AttributeSet attrs) {
super(context, attrs);
CustomFontHelper.setCustomFont(this, context, attrs);
}
public ButtonPlus(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
CustomFontHelper.setCustomFont(this, context, attrs);
}
}
And you can use inside your layout XML file.

Preview layout with merge root tag in Intellij IDEA/Android Studio

Let's imagine we are developing compound component based on LinearLayout. So, we create class like this:
public class SomeView extends LinearLayout {
public SomeView(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.VERTICAL);
View.inflate(context, R.layout.somelayout, this);
}
}
If we'll use LinearLayout as a root of somelayout.xml, we'll have extra view level, so we use merge tag:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some text"
android:textSize="20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some other text"/>
</merge>
But in Preview tab in IDE merge always acts as FrameLayout, and we'll see something like that:
(It is Android Studio, Intellij IDEA is just the same, about Eclipse I don't know)
Preview speed up developing layouts a lot, it's sad lose such a great help even for some layouts. May be there is a way to specify, how Preview should interpret merge tag in particular layout?
There is a new parentTag tools attribute (added in Android Studio 2.2) that you can use to specify the layout type for a merge tag, which will make the layout render correctly in the layout editor preview.
So using your example:
<merge 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:parentTag="LinearLayout"
tools:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some text"
android:textSize="20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some other text"/>
</merge>
Note: Both android:layout_width and android:layout_height must be specified in order for the layout to display properly in the editor.
Edit: Outdated answer. See answer by starkej2.
Android Studio 0.5.8 added support for tools:showIn. By using it it is possible to preview < merge > layouts.
http://tools.android.com/recent/androidstudio058released
layout/layout_merge.xml with tools:showIn:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="#layout/simple_relativelayout">
......
</merge>
layout/simple_relativelayout.xml with include:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/layout_merge"/>
</RelativeLayout>
Is also possible use custom class as parent instead of merge like
<com.mycompany.SomeView xmlns:android="http://schemas.android.com/apk/res/android">
...
</com.mycompany.SomeView>
And then directly inflate this layout and cast result view to SomeView.
Android studio will directly check parent class of SomeView and handle preview like LinerLayout.
You can use onFinishInflate() method in the SomeView to bind views by findViewById().
Benefit of this solution is that you can put all layout definitions or style definition directly to the layout file, you can't use method like setOrientation() in code.

Can I set a custom attribute on an android layout include tag?

I'm trying to set a custom attribute on an include tag for a layout whose root is a custom view:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:archxs="http://schemas.android.com/apk/res/com.archxs.bincalc"
android:id="#+id/calculatorRowMenuAnchor"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:visibility="gone">
<include android:id="#+id/calculatorrowmenu_result_running"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
archxs:isRunningResult="true"
layout="#layout/single_line_result" />
...
includes:
<?xml version="1.0" encoding="utf-8"?>
<com.archxs.bincalc.SmallIntegerResultView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:clickable="true">
...
</com.archxs.bincalc.SmallIntegerResultView>
but the custom attribute is not set:
public SmallIntegerResultView(Context context, AttributeSet attrs) {
super(context,attrs);
final TypedArray styled = context.obtainStyledAttributes(attrs, R.styleable.ResultView);
try {
m_isRunningResult = styled.getBoolean(R.styleable.ResultView_isRunningResult, false);
} finally {
styled.recycle();
}
}
Should this work? If not why? If yes what am I doing wrong?
Thanks all?
Sorry it is maybe a little late but as I had a similar problem :
did you declare your custom attribute in attrs.xml ?
Look at this link for more explanations : custom-xml-attributes-for-android-widgets

Custom view in xml layout

I've created my own view by creating a subclass of the SurfaceView class.
However I can't figure out how to add it from the xml layout file. My current main.xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<View
class="com.chainparticles.ChainView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
What have I missed?
Edit
More info
My view looks like this
package com.chainparticles;
public class ChainView extends SurfaceView implements SurfaceHolder.Callback {
public ChainView(Context context) {
super(context);
getHolder().addCallback(this);
}
// Other stuff
}
And it works fine like this:
ChainView cview = new ChainView(this);
setContentView(cview);
But nothing happens when trying to use it from the xml.
You want:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.chainparticles.ChainView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Edit:
After seeing the rest of your code it's probably throwing because you can't call getHolder in the constructor while being inflated. Move that to View#onFinishInflate
So:
#Override
protected void onFinishInflate() {
getHolder().addCallback(this);
}
If that doesn't work try putting that in an init function that you call in your Activitys onCreate after setContentView.
It was probably working before because when inflating from xml the constructor:
View(Context, AttributeSet) is called instead of View(Context).
What you missed in your example was the tag name, it supposed to be "view" (first non-capital) not "View". Although you can put your class name as the tag name most of the time, it's impossible to do that if your class is inner class, because "$" symbol, which is used in Java to reference inner classes is restricted in XML tags.
So, if you want to use inner class in your XML you should write like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<view
class="com.chainparticles.Foo$InnerClassChainView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
The thing is that both "view" and "View" tags exist in the schema. "View" tag (started with capital letter) will generate a View class, while "view" tag, when parsed, will examine the class attribute.

Reusing layout XML and the code behind

I am trying to turn a couple buttons into a reusable component in Android. I have successfully gotten the XML / UI portion working, but I can't figure out how to make code behind it reusable between activities, short of recoding it everywhere. I am new to Android, so I apologize if this is obvious.
I've already reviewed this post several times: Android layout Tricks 3 - Part 1 but it seems to be missing a few files, and I do not have enough experience to rebuild them.
A dumbed down version of my main layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<WebView android:id="#+id/webview"
android:layout_width="fill_parent"
android:layout_height="375px"
android:layout_alignParentTop="true" />
<include layout="#layout/navbar"/>
</RelativeLayout>
and then of my "component":
<?xml version="1.0" encoding="UTF-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center">
<ImageButton android:id="#+id/Button1"
android:layout_width="71px"
android:layout_height="wrap_content"
android:background="#drawable/button1"
android:layout_alignParentBottom="true" />
<ImageButton android:id="#+id/Button2"
android:layout_width="75px"
android:layout_height="wrap_content"
android:background="#drawable/button1"
android:layout_toRightOf = "#+id/Button1"
android:layout_alignParentBottom="true" />
</LinearLayout>
</merge>
If you have any additional critiques on my XML, I would appreciate that too.
What I do is make an actual component that contains all of the common code and use it directly. Here is a dumbed down version of the component class:
public class NavigationBar extends LinearLayout {
public NavigationBar(Context context) {
super(context);
setupView(context);
hookupButtons(context);
}
public NavigationBar(Context context, AttributeSet attrs) {
super(context, attrs);
setupView(context);
hookupButtons(context);
}
private void setupView(Context context) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// inflate whatever layout xml has your common xml
inflater.inflate(R.layout.navigation_bar, this);
}
}
In my class hookupButtons does exactly what you think it would do. :-)
Then my in all my layout xmls look similar to this:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.dragonglobal.dragonplayer.ui.widgets.NavigationBar
android:id="#+id/nav_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ListView
android:id="#+id/list_of_playlists"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
In the onCreate of each activity I also have this (that you can adapt to whatever you need):
NavigationBar navbar = (NavigationBar) findViewById(R.id.nav_bar);
navbar.setText("Playlists");
Of course you will need to add whatever imports you need.
EDIT
Just a clarification: My navigation_bar.xml looks very similar to yours except I don't have the merge lines in mine.
EDIT 2
Here is what hookupButtons looks like. I'm only showing one button but you should get the idea.
private void hookupButtons(final Context context) {
ImageButton playlistsBtn = (ImageButton)findViewById(R.id.nav_playlists_btn);
if (context instanceof PlaylistsActivity) {
playlistsBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.nav_playlists_active));
} else {
playlistsBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(context, PlaylistsActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
context.startActivity(i);
}
});
}
}
By using in XML layout, you're making only the layout reusable, not any Java code that uses it.
You must create a subclass of View, if you want to reuse Java logic as well. The tutorial from your link has a sample that fits your need very well:
public class OkCancelBar extends LinearLayout {
...

Categories

Resources