Custom view in xml layout - android

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.

Related

Android ListFragment #id attribute

I place two ListFragment in my MainActivity.
This is the ListFragment xml file: fragment1.xml
<?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" >
<ListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false" />
</LinearLayout>
My question is, why must I use android:id="#id/android:list" here? When I use, e.g., #+id/frag_list, the program crashes with Error "inflating class fragment".
ListActivity has a default layout that consists of a single, full-screen list in the center of the screen. However, if you desire, you can customize the screen layout by setting your own view layout with setContentView() in onCreate(). To do this, your own view MUST contain a ListView object with the id "#android:id/list" (or list if it's in code). Its same when your class extends ListFragment.
For more info do check the docs
http://developer.android.com/reference/android/app/ListActivity.html.
You can extend Fragment instead of ListFragment. Have a custom layout with ListView. Then you can provide any id for your listview.

Using two setContentView in one activity class

I have the following code where MyClass basically extends View. I was wondering if I need to use both setContentView(R.layout.activity_mainlcass_app) and setContentView(myDrawing) to show the 2D graphics that I draw in MyClass.
public class MainClass extends Activity {
MyClass myDrawing;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mainlcass_app);
myDrawing = new myDrawing(this);
setContentView(myDrawing);
myDrawing.requestFocus();
}
}
No, You can't do that. The second layout will override on the parent view.
In you main layout (activity_mainlcass_app) just add MyClass
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.example.MyClass
android:id="#+id/myclass"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
Try like this
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.example.firstactivity
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<com.example.secondactivity
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
For more information check this link and this example
If you want new drawing on top of other (with different layouts sizes maybe) use FrameLayout for original layout and use gravity to position new drawing and use addView methods of activity.

custom view becomes invisible in xml layout

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.

How do I add a custom view to ViewFlipper

I have a ViewFlipper defined that contains 3 views...
<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/flipper" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include android:id="#+id/first" layout="#layout/first_view" />
<include android:id="#+id/second" layout="#layout/second_view" />
<include android:id="#+id/third" layout="#layout/third_view" />
</ViewFlipper>
I also have a custom View defined within my Activity...
private class CompassView extends View {
#Override
protected void onDraw(Canvas canvas) {
...
}
}
Some how, I need these linked together so that the 'third_view' defined in the XML layout file needs to be a CompassView, or have a CompassView added to it.
What I can do is drop the 'third_view' from the layout and then add in the CompassView manually..
viewFlipper = (ViewFlipper)findViewById(R.id.flipper);
viewFlipper.addView(new CompassView(this));
But then I lose the ability to define other view controls within the layout file.
Can I add CompassView to 'third_view' declaratively?
If the question is how to add a custom view in an Android XML layout file, try this:
<com.example.CustomView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</com.example.CustomView>
The open and close tags should just be the fully qualified class of your custom view.

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