Get View by ID from attributes in Custom View Class - android

I want to get a view from his ID, from the attribute in the xml. I have tried with getParent() but it's return null.
XML
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ntwldg="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="#drawable/background_settings"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/revealView"
android:gravity="center"
android:text="TEST"
android:background="#android:color/darker_gray"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.dot.networkloading.NetworkLoading
android:id="#+id/network_loading"
ntwldg:text="Youtube"
ntwldg:image="#drawable/ic_youtube"
ntwldg:imageBackground="#drawable/ic_youtube"
ntwldg:revealView="#id/revealView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
The attribute revealView is referencing the View above.
Code - NetworkLoading (init())
title = (TextView) findViewById(R.id.title);
image = (ImageView) findViewById(R.id.image);
imageBackground = (ImageView) findViewById(R.id.imageBackground);
finishView = findViewById(R.id.revealView);
String text = attributes.getString(R.styleable.network_loading_text);
imageId = attributes.getResourceId(R.styleable.network_loading_image, 0);
imageBackgroundId = attributes.getResourceId(R.styleable.network_loading_imageBackground, 0);
finishView = ((View) getParent()).findViewById(attributes.getResourceId(R.styleable.network_loading_revealView, R.id.revealView));

It seems that you're trying to find your revealView too early. In the constructor, the View will not have yet been added to the layout it's in, so getParent() will return null. Keep the resource ID for the revealView as a field, get its value in the constructor, and then find the View in the onAttachedToWindow() method.
In the code you've posted, remove the last line - the last finishView = ... line - and instead save the resource ID to your field.
revealViewId = attributes.getResourceId(R.styleable.NetworkLoading_revealView, R.id.revealView);
Then find the View in the onAttachedToWindow() method instead.
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
finishView = ((View) getParent()).findViewById(revealViewId);
...
}

Related

why dynamically set text to TextView not visible in popup window while hard coded is

I am trying to generate popup window containing dynamically generated text. log output clearly shows that the desired text is actually set to textView but I can't understand why it is not showing on the app.
MainActivity.java
#Override
public boolean onOptionsItemSelected(MenuItem item) {
linearLayout = (LinearLayout) findViewById(R.id.main_activity_parent_layout);
int id = item.getItemId();
if(id == R.id.info_button){
layoutInflater = (LayoutInflater) getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);
//Updating a textview in different layout xml from the main activity
LinearLayout vi = (LinearLayout)layoutInflater.inflate(R.layout.activity_info, null);
TextView textView = vi.findViewById(R.id.info);
textView.setText(R.string.main_activity_info);
Log.i("MainActivity",String.valueOf(textView.getText()));
ViewGroup container = (ViewGroup)layoutInflater.inflate(R.layout.activity_info,null);
popupWindow = new PopupWindow(container, WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,true);
popupWindow.setOutsideTouchable(true);
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
//Note showAtLocation method should always in end for proper rendering of poup Window
popupWindow.showAtLocation(linearLayout,Gravity.TOP,0,100);
}
return super.onOptionsItemSelected(item);
}
activity_info.xml
<?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">
<TextView
android:id="#+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:padding="8dp"
android:text="hello"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="#android:color/black"/>
</LinearLayout>
popup window show hello which is hardcoded text.
You are inflating R.layout.activity_info two times and losing the TextView you are changing in the process. Make the following change to keep the first inflation and your modification:
popupWindow = new PopupWindow(vi, WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,true);

ButterKnife binding from parent view [duplicate]

I have a layout where I include the same sub-layout multiple times, each one with a different role:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<include
android:id="#+id/settings_eco_seekarc"
android:layout_width="match_parent"
android:layout_height="match_parent"
layout="#layout/settings_arc" />
<include
android:id="#+id/settings_comfort_seekarc"
android:layout_width="match_parent"
android:layout_height="match_parent"
layout="#layout/settings_arc" />
</LinearLayout>
It works if I find the views in this way:
View eco = root.findViewById(R.id.settings_eco_seekarc);
mEcoSeekArc = (SeekArc) eco.findViewById(R.id.settings_seekarc);
mEcoLeaf = (ImageView) eco.findViewById(R.id.settings_leaf_img);
mEcoText = (TextView) eco.findViewById(R.id.settings_text);
View cmf = root.findViewById(R.id.settings_comfort_seekarc);
mComfortSeekArc = (SeekArc) cmf.findViewById(R.id.settings_seekarc);
mComfortLeaf = (ImageView) cmf.findViewById(R.id.settings_leaf_img);
mComfortText = (TextView) cmf.findViewById(R.id.settings_text);
I am introducing ButterKnife in my project now, and I hoped I could simply annotate each view (the following obviously doesn't work, and I can see why) and inject them later using each included layout root:
#InjectView(R.id.settings_seekarc)
SeekArc mEcoSeekArc;
#InjectView(R.id.settings_leaf_img)
ImageView mEcoLeaf;
#InjectView(R.id.settings_text)
TextView mEcoText;
#InjectView(R.id.settings_seekarc)
SeekArc mComfortSeekArc;
#InjectView(R.id.settings_leaf_img)
ImageView mComfortLeaf;
#InjectView(R.id.settings_text)
TextView mComfortText;
//then later...
View eco = root.findViewById(R.id.settings_eco_seekarc);
ButterKnife.inject(this, eco);
View cmf = root.findViewById(R.id.settings_comfort_seekarc);
ButterKnife.inject(this, cmf);
Doing it in this way, though, leads me to this error at the second injection:
Error:(81, 13) error: Attempt to use #InjectView for an already
injected ID 2131493185 on 'mEcoSeekArc'.
My question is: is there a way to use ButterKnife in this scenario?
you could use some type of sub-container like this:
public static class SettingsArcLayout {
#InjectView(R.id.settings_text) public TextView mEcoText;
#InjectView(R.id.settings_leaf_img) public ImageView mComfortLeaf;
// etc...
}
then you have it
SettingsArcLayout layout1 = new SettingsArcLayout();
SettingsArcLayout layout2 = new SettingsArcLayout();
and then:
ButterKnife.inject(this); // inject eco and cmf
ButterKnife.inject(layout1, eco);
ButterKnife.inject(layout2, cmf);
and throught this class you can use:
layout1.mEcoText.setText(... etc
The idea of my answer is the same as Budius proposed, I found it in a related issue on ButterKnife's github repo. Original Author is TomazMartins
The MainActivity:
public MainActivity extends AppCompatActivity {
// 1. First, we declare the layout that was included as a View objects.
#BindView(R.id.layout_1) View layout_1;
#BindView(R.id.layout_2) View layout_2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 2. In here, we bind the included layouts
ButterKnife.bind(this);
// 4. Then, we create objects of the type of the IncludedLayout.
// In this example the layout reuse the same layout twice, so, there are two
// IncludedLayouts.
IncludedLayout includedLayout_1 = new IncludedLayout();
IncludedLayout includedLayout_2 = new IncludedLayout();
// 5. We bind the elements of the included layouts.
ButerKnife.bind(includedLayout_1, layout_1);
ButerKnife.bind(includedLayout_2, layout_2);
// 6. And, finally, we use them.
includedLayout_1.displayed_text.setText("Hello");
includedLayout_2.displayed_text.setText("Hey!");
}
// 3. We create a static class that will be an container of the elements
// of the included layout. In here we declare the components that
// hold this. In this example, there is only one TextView.
static class IncludedLayout {
#BindView(R.id.displayed_text) TextView displayed_text;
}
}
The XML of the MainAcitvity:
<!--...-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<include android:id="#+id/layout_1" layout="#layout/included_layout" />
<include android:id="#+id/layout_2" layout="#layout/included_layout" />
</LinearLayout>
<!--...-->
The XML of the Included Layout:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/displayed_text"/>
</LinearLayout>
That's it!
When i ran it, although the id was the same, because I reused it, the text in the TextView was different.

NullPointerException on getTextView in Android

so I have this getter function in a Class called ItemEnergyGreen:
public TextView getTextView(FrameLayout fl) {
textView = (TextView) fl.findViewById(R.id.textview_energyOrange_quantity);
return textView;
}
And I want now to call this methode from another Class:
//Item Energy Green
itemEnergyGreenFrameLayout = (FrameLayout) inflater.inflate(R.layout.item_energy_green_layout, null, false);
itemEnergyGreenQuantityTextView = itemEnergyGreen.getTextView(itemEnergyGreenFrameLayout);
btn_ItemEnergyGreen = (ImageButton) itemEnergyGreenFrameLayout.findViewById(R.id.btn_energyGreenItem_use);
btn_ItemEnergyGreen.setOnClickListener(this);
The function call is in Line 2, I am passing the frameLayout to the getter Function but textView in my ItemEnergyGreen class is always NULL.
The error occurs when i want to call setText on my view:
public void itemEnergyGreenUpdateNumber() {
int quantity = itemEnergyGreen.getQuantity();
String qstring = String.valueOf(quantity);
itemEnergyGreenQuantityTextView.setText(qstring);
}
This is the XML-FrameLayout that is get inflated:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ItemEnergyGreenFrameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageButton
android:id="#+id/btn_energyGreenItem_use"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="#drawable/item_energydrink_green" >
</ImageButton>
<TextView
android:id="#+id/textview_energyGreen_quantity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#F00"
android:clickable="false"
android:padding="2dp"
android:textColor="#FFF"
android:textStyle="bold" >
</TextView>
</FrameLayout>
Why is that?
ps. At the point where the getter function is called, the itemEnergyGreen Object is already initialized.
Thank you for your answers, and sorry if that is a dump question but i´m going crazy about this.
textView in my ItemEnergyGreen class is always NULL.
findViewById looks for a view in the current view hierarchy. Probably TextView is not a child of FrameLayout. So initialization fails leading to NullPointerException.
The other reason could be that you referenced wrong id.
Edit:
Id referenced in wrong
<TextView
android:id="#+id/textview_energyGreen_quantity"
Change this
textView = (TextView) fl.findViewById(R.id.textview_energyOrange_quantity);
to
textView = (TextView) fl.findViewById(R.id.textview_energyGreen_quantity);
Try this
private View mView;
mView =inflater.inflate(R.layout.item_energy_green_layout, null, false);
itemEnergyGreenQuantityTextView = itemEnergyGreen.getTextView(mView);

how to get component given as reference in custom view?

Hi I am making a custom view and giving other component id as a reference in it like this
<com.example.timerview.CustomView
android:id="#+id/custom_view"
android:layout_width="100dip"
android:layout_height="100dip"
mtv:associatedTextView="#+id/text_view"
/>
<TextView
android:id="#+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
now I want to use this TextView in CustomView.java so I am doing this in constructor
int tId = a.getResourceId(R.styleable.CustomView_associatedTextView, 0);
TextView tText = (TextView) findViewById(tId);
but I found tText is null please advise me where I am wrong or How can I do such thing. Please help me.
Your TextView is not a child of your custom view, which is why findViewById cannot find it.
Call findViewById from the root view, after the custom view has been attached:
protected void onAttachedToWindow() {
super.onAttachedToWindow();
int tId = a.getResourceId(R.styleable.CustomView_associatedTextView, 0);
TextView tText = (TextView) getRootView().findViewById(tId);
}

Why do I keep getting a null reference to my LinearLayout?

I have a layout called view.xml which contains a View called view_related. Basically, in my dictionary app, if there are related words to an entry, I will replace view_related with a LinearLayout that contains a header "Related entries" and a bunch of TextViews representing every related word.
I keep getting a NullPointerException everytime I'm adding a TextView to the LinearLayout in my Activity's onCreate() method, and I don't understand why though my code looks pretty straightforward.
view.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView android:id="#+id/view_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12pt"
android:textColor="#fff"
android:textStyle="bold"
android:background="#990011"
android:padding="10dp"
android:text="lalala word"
/>
<ScrollView android:id="#+id/view_description"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/view_header">
<LinearLayout android:id="#+id/view_description_content"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="#string/demo_definition"
/>
<!-- THIS WILL BE REPLACED -->
<View android:id="#+id/view_related"
android:layout_width="match_parent"
android:layout_height="wrap_content"></View>
</LinearLayout>
</ScrollView>
</RelativeLayout>
view_related.xml, the LinearLayout that will replace the View element in view.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/view_related_entries"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:id="#+id/view_related_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:textColor="#fff"
android:textStyle="bold"
android:textSize="7pt"
android:background="#000"
android:text="Related entries"
/>
<LinearLayout android:id="#+id/view_related_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</LinearLayout>
</LinearLayout>
And finally, the onCreate method, which for now assumes the related entries are "Hello" and "Goodbye:"
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view);
LinearLayout ll = (LinearLayout) findViewById(R.id.view_related_list);
TextView tv = new TextView(this);
tv.setText("Hello");
ll.addView(tv); // NULL POINTER EXCEPTION
tv = new TextView(this);
tv.setText("Goodbye");
ll.addView(tv);
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View view = findViewById(R.id.view_related);
ViewGroup parent = (ViewGroup) view.getParent();
int index = parent.indexOfChild(view);
parent.removeView(view);
View llview = li.inflate(R.id.view_related_entries, parent, false);
parent.addView(llview, index);
}
setContentView(R.layout.view);
LinearLayout ll = (LinearLayout) findViewById(R.id.view_related_list);
The function findViewById only finds views that are actually set. Your current setContentView does not set an xml that has the id you are looking for in it, so the first line I quoted will not result in anything.
You should either load the correct XML, or inflate the view you are looking for with an inflater
the line (LinearLayout ll = (LinearLayout) findViewById(R.id.view_related_list);) will search for view_related_list in view.xml, as in the line before that is the view you are using..
You need to inflate view_related.xml first and then get the view from it..
You're doing a lot of wrong things in your code. First you search for a LinearLayout that isn't in the current layout and also isn't in any inflated layout at that moment. Second, you try to inflate an id reference instead of a layout reference. Last, you should use another approach for what you're trying to do. Your code should be(from what I understood):
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view);
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View view = findViewById(R.id.view_related);
ViewGroup parent = (ViewGroup) view.getParent();
int index = parent.indexOfChild(view);
parent.removeView(view);
View llview = li.inflate(R.layout.view_related, parent, false); // is view_related the name of the extra layout file?
parent.addView(llview, index);
LinearLayout ll = (LinearLayout) findViewById(R.id.view_related_list); // or search for it in llview, llview.findViewById(R.id.view_related_list);
TextView tv = new TextView(this);
tv.setText("Hello");
ll.addView(tv); // NULL POINTER EXCEPTION
tv = new TextView(this);
tv.setText("Goodbye");
ll.addView(tv);
}
This is a situation when you should use a ViewStub to add the new layout file. Although, I don't understand why don't you add the new layout file directly in the view.xml if you're going to add the layout's content in the onCreate method.
i think you need to use setContentView(R.layout.view_related); instead of setContentView(R.layout.view);
or another simple thing you can do is take the linear layout in the same layout "view" and make it invisible when not required and visible when required
You may forgetting to declare your Activity in manifest.xml

Categories

Resources