Get reference of custom view by id declared in xml from activity - android

I have a custom view that extends ImageView and I use it in an XML layout like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp">
<com.android.example.MyView
android:id="#+id/myview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp" />
<com.android.example.MyView
android:id="#+id/myview2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp" />
</LinearLayout>
</LinearLayout>
in my activity I do the usual: setContentView(R.layout.myLayout) .
Now, I need to get the reference of my class/View "MyView" in order to set a custom listener, but I i'm not able to get it from the id.
myview (MyView) findViewById(R.id.myview1);
returns null.
I tried to look at similar issues but haven't found any that helped me.
Please, note that if I add the View to the layout programmatically from the Activity everything is working fine, but I would like to be able to find what the issue is here.
Thanks in advance.

It does work.
The layout you're using for setContentView must be the same layout you have added your custom view to.

I found the issue was a stupid cut and paste mistake where I forgot to add the AttributeSet when calling the super()
having
public MyView(Context context, AttributeSet attrs) {
super(context);
}
instead of
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}

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.

Setting layout of a CustomView based on user input

I have a custom view extending the RelativeLayout. In the init(Context context, AttributeSet attrs) method of this class I set the layout file by:
inflate(getContext(), R.layout.in_session_view_layout, this);
I am using this custom view in a list item like this:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:verizon="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_margin="5dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<ImageView
android:id="#+id/flag"
android:layout_width="60dp"
android:layout_height="160dp"
android:layout_below="#id/txt"
android:layout_gravity="center"
android:layout_margin="5dp" />
</FrameLayout>
<com.widgets.FreeBeeNotificationView
android:id="#+id/freebee_pre_session_view"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_gravity="right|top"
android:layout_marginBottom="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="6dp"
verizon:textSize="12sp" />
</FrameLayout>
Now, the requirement is that, this layout file needs to be set in the custom view dynamically based on an user input. But, I receive the user input after the init() method of the custom view has already been called as this method gets called as soon as the FrameLayout given above gets loaded.
How do I dynamically set the layout file to the custom view based on user input? Can someone kindly help me.
Thanks.
Hope I have understood your requirement correctly. If not please explain further.
You can do this.
In your custom view make a method called setLayout(int layoutId)
public void setLayout(int layoutId)
{
removeAllViews();
LayoutInflater inflater = LayoutInflater.from(getContext());
inflater.inflate(getContext(), layoutId, this);
}
When you have your user input you call
yourCustomView.setLayout(R.layout.new_layout);
Disclaimer: All this is from memory and not tested so might not compile.

Android programming - How to acces [to draw on] XML view in main.xml layout, using code

Ok I'm a newbie at Android programming, have a hard time with the graphics part. Understand the beauty of creating layout in XML file, but lost how to access various elements, especially a View element to draw on it.
See example of my layout main.xml here;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Title" android:text="App title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:background="#A0A0FF"/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/PaperLayout"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:focusable="true">
<View
android:id="#+id/Paper"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:id="#+id/File"
android:layout_width="fill_parent"
android:layout_weight="1"
android:layout_height="34dp"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:clickable="true" android:textSize="10sp"
android:text="File" />
<Button
android:id="#+id/Edit"
android:layout_width="fill_parent"
android:layout_weight="1"
android:layout_height="34dp"
android:clickable="true"
android:textSize="10sp" android:text="Edit" />
</LinearLayout>
</LinearLayout>
As you can see I have a custom app title bar, then a View filling middle, and finally two buttons in the bottom. Catching buttons' events and responding to, for example changing title bar text and changing View background color works fine, but how the heck do I access and more importantly draw on the view defined in main.xml
UPDATE:
Thank you very much for your suggestion, however besides that I need a View, not ImageView and you are missing a parameter on canvas.drawText() and an ending bracket, it does not work.
Now this is most likely because you missed the fact that I am a newbie and assuming I can fill in any blanks.
Now first of all I do NOT understand why in my main.xml layout file I can create a View or even a SurfaceView element, which is what I need, but according to your solution I don't even specify the View like <View ....../>
Anyways I edited my main.xml according to your solution, and slimmed it down a bit for simplicity;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Title" android:text="App title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:background="#A0A0FF"/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/PaperLayout"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:focusable="true">
<com.example.MyApp.CustomView
android:id="#+id/Paper"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<com.example.colorbook.CustomView/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:id="#+id/File"
android:layout_width="fill_parent"
android:layout_weight="1"
android:layout_height="34dp"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:clickable="true"
android:textSize="10sp"
android:text="File" />
</LinearLayout>
</LinearLayout>
In my main java file MyApp.java. I added this after onCreate();
public class CustomView extends ImageView {
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText("Your Text", 1, 1, null);
}
}
But I get error on the CustomView part;
"Implicit super constructor ImageView() is undefined for default constructor.Must define an explicit constructor"
Eclipse suggests 3 quick fixes about adding constructor, but none helps, well it removes error but gives error on app when running.
I hope somebody can break this down for me and provide a solution, and perhaps explain why I can't just create a View element in my main.xml layout file and draw on it in code.
UPDATE:
Ok I am still trying to use your solution, which is still giving me problems and various errors. But first and foremost I still do NOT understand why I have to create a custom class to use in my layout, when I have to option to even use the wysiwyg layout editor to insert a View element and "just" draw on that in my main, well for now only code file. So pleeeeeease someone answer me that one.
Anyways now I have;
package com.example.myapp;
import com.example.myapp.CustomView;
//and here comes other import
public class MyApp extends Activity {
//rest of code including OnCreate()
And I created a new class, new file CustomView.Java, where I directly pasted your code so it looks like;
public class CustomView extends ImageView {
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setARGB(255, 150, 205, 129);
paint.setTextSize(20);
canvas.drawText("Your Text", 1, 1, paint);
}
}
Ok so this class code wants me to add imports for ImageView, Canvas and Paint, which I did, and then again I am back to the error the public class *CustomView* part;
"Implicit super constructor ImageView() is undefined for default constructor.Must define an explicit constructor".
I appreciate you trying to help me, THANKS!
To draw on a view, creat your own custom view.
To do so, you need to add a new class. With eclipse it's just File->New->Class and there you go. Override the onDraw()-Method to fit your needs and add your CustomView to your Layout:
public class CustomView extends ImageView {
// The needed constructors:
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setARGB(255, 150, 205, 129);
paint.setTextSize(20);
canvas.drawText("Your Text", xposition, yposition, paint);
}
}
In your xml-File you add your CustomView like this:
<com.example.CustomView
android:id="#+id/yourID"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_margin="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.example.CustomView>
If you wan't to draw onto a drawable from your res-Folder, specifiy the "src"-parameter of your customView.
override the onCreate method and then use the method findViewById. For example to use and modify the view background color use the following :
View v = (View)findViewById(R.id.Paper);
v.setBackgroundColor(myColor);
Similarly modify any other view/Widget defined in your layout
to use the view defined in main.xml in an Activity, override Activity's onCreate method such as:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
edit: sorry, I misread "draw on view" as "draw view" in your question :) See L0rdAli3n's answer for that.

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.

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