findViewById of a Constraint Layout returns null - java

I have a problem with findViewById using Java in Android Studio. I'm triying to obtain a Constraint Layout to use .addview in it but it returns null.
This is the layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/gameLayout"
tools:context=".GameActivity">
This is the line with problems:
ConstraintLayout mainLayout = (ConstraintLayout) findViewById(R.id.gameLayout);
And it returns null, what am I doing bad?
Thanks
Edit: Now I'm getting stucked afther this loops, what can be?
protected void generateGameZone(int m, int n){
LinearLayout[] main_layouts = new LinearLayout[m];
for(int i=0;i<main_layouts.length;i++){
main_layouts[i] = new LinearLayout(this);
main_layouts[i].setOrientation(LinearLayout.HORIZONTAL);
main_layouts[i].setLayoutParams(new LinearLayout.LayoutParams(30,30));
mainLayout.addView(main_layouts[i]);
}
LinearLayout[][] secondary_layouts = new LinearLayout[m][n];
for(int i=0;i<secondary_layouts.length;i++){
for(int j=0;j<secondary_layouts[i].length;j++){
secondary_layouts[i][j] = new LinearLayout(this);
secondary_layouts[i][j].setOrientation(LinearLayout.HORIZONTAL);
secondary_layouts[i][j].setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
TextView txtBox = new TextView(this);
txtBox.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
txtBox.setId(i*10 + j);
secondary_layouts[i][j].addView(txtBox);
main_layouts[i].addView(secondary_layouts[i][j]);
}
}
}
I obtain a black screen
Edit2: Black screen solved, now the layout I create with loops its not being showed

From your question it seems like you are trying to add the ConstraintLayout programmatically to your activity. However findViewById(int) called from an Activity tries to find the already existing view in the hierarchy and returns null if it isn't found.
I think what you are looking for is either to inflate the layout using a LayoutInflater and then add it using addView as you suggested, or if this layout represents the root of your activity, use setContentView(int) to let the activity handle the inflation.

Related

How add array of TextViews into Relative layout without overlapping programmatically in android?

I'm looking for a solution to solve my problem which all my TextViews overlaps on themselves, when are added to Relative Layout. In fact, I need to do put them after each. other I've read existed answers, I followed them but nothing could solve it yet. can someone tell me where I did wrongly?
here is my code:
for (int i=0;i<parts.length;i++)
{
valueTV[i] = new TextView(this);
valueTV[i].setText(parts[i]);
valueTV[i].setId(i);
valueTV[i].setWidth(300);
RelativeLayout.LayoutParams lparams = new RelativeLayout.LayoutParams
(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
linearLayout_Skills.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
}
linearLayout_Skills.setBackgroundColor(getResources().getColor(R.color.blue));
if(i>=1)
{
lparams.addRule(RelativeLayout.END_OF, valueTV[i-1].getId());
valueTV[i].setLayoutParams(lparams);
}else {
lparams.addRule(RelativeLayout.ALIGN_PARENT_START);
valueTV[i].setLayoutParams(lparams);
}
linearLayout_Skills.addView(valueTV[i]);
}
XML code:
<RelativeLayout
android:id="#+id/linearSkills"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="rtl"
android:paddingTop="5dp"
</RelativeLayout>
You can achieve this using Relative layout
So this is the main idea , first you define your relation layout
//layout variable is your relative layout
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
layout.setLayoutParams(layoutParams);
Then you define a param variable like this
RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
After that you define your textView with an id (in your case this id can be its position in the array)
TextView tv1 = new TextView(this);
tv1.setId(1);
tv1.setText("textView1");
The next textView will be declared like this
TextView tv2 = new TextView(this);
params1.addRule(RelativeLayout.BELOW, tv1.getId());
tv2.setId(2);
tv2.setText("textView2");
Finally you set your view using the params you defined
layout.addView(tv2, params1);
Here is a complete example you can check answer by #AndiM

Programatically add LinearLayout with Text and Image

I'm trying to add a LinearLayout for each item in a varying Array. I need each item to have an image and text horizontally, but for now I am testing with the text.
Keeping in mind this code is in a Fragment.
I think the error is with the getContext() but not to sure.
The code I currently have is:
List<PaymentOption> paymentOptions = aTradeItem.getPaymentOptions();
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(ImageUtils.dpToPx(16), ImageUtils.dpToPx(4), ImageUtils.dpToPx(16), ImageUtils.dpToPx(4));
LinearLayout.LayoutParams lineparams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ImageUtils.dpToPx(1));
lineparams.setMargins(0, ImageUtils.dpToPx(4), 0, ImageUtils.dpToPx(4));
if (paymentOptions != null && paymentOptions.size() > 0) {
for (PaymentOption t : paymentOptions) {
LinearLayout paymentOptionLayout = new LinearLayout(getContext());
paymentOptionLayout.setOrientation(LinearLayout.HORIZONTAL);
paymentOptionLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
TextView heading = new TextView(getContext());
heading.setText(t.getDescription());
heading.setTextColor(getResources().getColor(R.color.light_text));
heading.setLayoutParams(lp);
paymentOptionLayout.addView(heading);
}
}
There are no errors, the data just doesnt populate on the screen. I have tried Hardcoding random text in the setText() but with no success.
Thank you
You're not adding your paymentOptionLayout to the layout which is set as your content View. Basically what you're doing is programatically creating the layout, but then doing nothing with it.
By default your activity_main.xml file will come with some type of layout depending on how you setup your code, for example a blank activity's xml file would be
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity"
android:id="#+id/RelativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
However when you create layouts programmatically the way you did, you must append them to the layout which is the parent layout in your XML file.
So I think what you need to do is the following.
RelativeLayout rl=(RelativeLayout)findViewById(R.id.RelativeLayout); //getting the view from the xml file. Keep in mind that the id is defiend in the xml file by you
List<PaymentOption> paymentOptions = aTradeItem.getPaymentOptions();
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(ImageUtils.dpToPx(16), ImageUtils.dpToPx(4), ImageUtils.dpToPx(16), ImageUtils.dpToPx(4));
LinearLayout.LayoutParams lineparams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ImageUtils.dpToPx(1));
lineparams.setMargins(0, ImageUtils.dpToPx(4), 0, ImageUtils.dpToPx(4));
if (paymentOptions != null && paymentOptions.size() > 0) {
for (PaymentOption t : paymentOptions) {
LinearLayout paymentOptionLayout = new LinearLayout(getContext());
paymentOptionLayout.setOrientation(LinearLayout.HORIZONTAL);
paymentOptionLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
TextView heading = new TextView(getContext());
heading.setText(t.getDescription());
heading.setTextColor(getResources().getColor(R.color.light_text));
heading.setLayoutParams(lp);
paymentOptionLayout.addView(heading);
rl.addView(paymentOptionLayout); //adding the view to the parent view
}
}
Please note that from the looks of your code, you're really just reimplementing listView which is an available layout in android. I think you should take a look at that.
getContext() is a method of activity class. It returns the context view only for currently running activity.
For Fragment either pass the instance of current activity class via constructor or use getActivity() method or this instead of getContext()
See here for help
Using context in a fragment
How to add view into LinearLayout of Fragment by onClick?
Also add paymentOptionLayout to the parent layout view right after for loop.

The specified child already has a parent. You must call removeView() on the child's parent first (Android)

I have to switch between two layouts frequently. The error is happening in the layout posted below.
When my layout is called the first time, there doesn't occur any error and everything's fine. When I then call a different layout (a blank one) and afterwards call my layout a second time, it throws the following error:
> FATAL EXCEPTION: main
> java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
My layout-code looks like this:
tv = new TextView(getApplicationContext()); // are initialized somewhere else
et = new EditText(getApplicationContext()); // in the code
private void ConsoleWindow(){
runOnUiThread(new Runnable(){
#Override
public void run(){
// MY LAYOUT:
setContentView(R.layout.activity_console);
// LINEAR LAYOUT
LinearLayout layout=new LinearLayout(getApplicationContext());
layout.setOrientation(LinearLayout.VERTICAL);
setContentView(layout);
// TEXTVIEW
layout.addView(tv); // <========== ERROR IN THIS LINE DURING 2ND RUN
// EDITTEXT
et.setHint("Enter Command");
layout.addView(et);
}
}
}
I know this question has been asked before, but it didn't help in my case.
The error message says what You should do.
// TEXTVIEW
if(tv.getParent() != null) {
((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}
layout.addView(tv); // <========== ERROR IN THIS LINE DURING 2ND RUN
// EDITTEXT
simply pass the argument
attachtoroot = false
View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);
I came here on searching the error with my recyclerview but the solution didn't work (obviously). I have written the cause and the solution for it in case of recyclerview. Hope it helps someone.
The error is caused if in the onCreateViewHolder() the following method is followed:
layoutInflater = LayoutInflater.from(context);
return new VH(layoutInflater.inflate(R.layout.single_row, parent));
Instead it should be
return new VH(layoutInflater.inflate(R.layout.single_row, null));
I got this message while trying to commit a fragment using attach to root to true instead of false, like so:
return inflater.inflate(R.layout.fragment_profile, container, true)
After doing:
return inflater.inflate(R.layout.fragment_profile, container, false)
It worked.
You must first remove the child view from its parent.
If your project is in Kotlin, your solution will look slightly different than Java. Kotlin simplifies casting with as?, returning null if left side is null or cast fails.
(childView.parent as? ViewGroup)?.removeView(childView)
newParent.addView(childView)
Kotlin Extension Solution
If you need to do this more than once, add this extension to make your code more readable.
childView.removeSelf()
fun View?.removeSelf() {
this ?: return
val parentView = parent as? ViewGroup ?: return
parentView.removeView(this)
}
It will safely do nothing if this View is null, parent view is null, or parent view is not a ViewGroup
frameLayout.addView(bannerAdView); <----- if you get error on this line the do like below..
if (bannerAdView.getParent() != null)
((ViewGroup) bannerAdView.getParent()).removeView(bannerAdView);
frameLayout.addView(bannerAdView); <------ now added view
If other solution is not working like:
View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);
check for what are you returning from onCreateView of fragment is it single view or viewgroup? in my case I had viewpager on root of xml of fragment and I was returning viewpager, when i added viewgroup in layout i didnt updated that i have to return viewgroup now, not viewpager(view).
My error was define the view like this:
view = inflater.inflate(R.layout.qr_fragment, container);
It was missing:
view = inflater.inflate(R.layout.qr_fragment, container, false);
In my case it happens when i want add view by parent to other view
View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(lyt); // -> crash
you must add parent view like this
View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(root);
Simplified in KOTLIN
viewToRemove?.apply {
if (parent != null) {
(parent as ViewGroup).removeView(this)
}
}
In my case, I had id named as "root" for constraint layout, which was conflicting the existing parent root id.
Try to change the id.
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/root" //<--It should not named as root.
android:layout_width="match_parent"
android:layout_height="match_parent"
</androidx.constraintlayout.widget.ConstraintLayout>
In my case the problem was caused by the fact that I was inflating parent View with <merge> layout. In this case, addView() caused the crash.
View to_add = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, true);
// parent_layout.addView(to_add); // THIS CAUSED THE CRASH
Removing addView() helped to solve the problem.
The code below solved it for me:
#Override
public void onDestroyView() {
if (getView() != null) {
ViewGroup parent = (ViewGroup) getView().getParent();
parent.removeAllViews();
}
super.onDestroyView();
}
Note: The error was from my fragment class and by overriding the onDestroy method like this, I could solve it.
My problem is related to many of the other answers, but a little bit different reason for needing to make the change... I was trying to convert an Activity to a Fragment. So I moved the inflate code from onCreate to onCreateView, but I forgot to convert from setContentView to the inflate method, and the same IllegalStateException brought me to this page.
I changed this:
binding = DataBindingUtil.setContentView(requireActivity(), R.layout.my_fragment)
to this:
binding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false)
That solved the problem.
You just need to pass attachToRoot parameter false.
mBinding = FragmentCategoryBinding.inflate(inflater, container, false)
If you're using ViewBinding, make sure you're referring to the right binding!
I had this issue when I was trying to inflate a custom dialog from within an activity:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final AlertBinding alertBinding = AlertBinding.inflate(LayoutInflater.from(this), null, false);
builder.setView(binding.getRoot()); // <--- I was using binding (which is my Activity's binding), instead of alertBinding.
This is how I do my custom dialog
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
android.view.View views = getLayoutInflater().inflate(layout_file, null, false);
builder.setView(views);
dialog = builder.create();
dialog.show();
I changed it into this and its works for me, I hope this helps
Dialog dialog = new Dialog(MainActivity.this);
dialog.setContentView(layout_file);
dialog.show();
check if you already added the view
if (textView.getParent() == null)
layout.addView(textView);
if(tv!= null){
((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}
I was facing the same error, and look what I was doing. My bad, I was trying to add the same view NativeAdView to the multiple FrameLayouts, resolved by creating a separate view NativeAdView for each FrameLayout, Thanks
In my case I was accidentally returning a child view from within Layout.onCreateView() as shown below:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v= inflater.inflate(R.layout.activity_deliveries, container, false);
RecyclerView rv = (RecyclerView) v.findViewById(R.id.deliver_list);
return rv; // <- here's the issue
}
The solution was to return the parent view (v) instead of the child view (rv).
I found another fix:
if (mView.getParent() == null) {
myDialog = new Dialog(MainActivity.this);
myDialog.setContentView(mView);
createAlgorithmDialog();
} else {
createAlgorithmDialog();
}
Here i just have an if statement check if the view had a parent and if it didn't Create the new dialog, set the contentView and show the dialog in my "createAlgorithmDialog()" method.
This also sets the positive and negative buttons (ok and cancel buttons) up with onClickListeners.
In my case, I had an adapter which worked with a recyclerView, the items that were being passed to the adapter were items with their own views.
What was required was just a LinearLayout to act as a container for every item passed, so what I was doing was to grab the item in the specified position inside onBindViewHolder then add it to the LinearLayout, which was then displayed.
Checking the basics in docs,
When an item scrolls off the screen, RecyclerView doesn't destroy its
view
Therefore, with my items, when I scroll towards a direction, then change towards the opposite direction - fast, the racently displayed items have not been destroyed, meaning, the items are still associated with the LinearLayout container, then on my end, I'm trying to attach to another container, which ends up with a child having a parent already.
My solution was to check if the specified item has a parent, if it has, I assign it to a variable, then call parentVar.removeView(item), then assign the new parent.
Here's the sample code(Problematic Adapter):
override fun onBindViewHolder(holder: QuestionWidgetViewHolder, position: Int) {
holder.linearLayoutContainer.removeAllViewsInLayout()
val questionWidget: QuestionWidget =
dataSource[position]
questionWidget.setValueChangedListener(this)
holder.linearLayoutContainer.addView(questionWidget)/*addView throws error once in a while*/
}
inner class QuestionWidgetViewHolder(mView: View) :
RecyclerView.ViewHolder(mView) {
val linearLayoutContainer: LinearLayout =
mView.findViewById(R.id.custom_question_widget_container)
}
Content of the R.id.custom_question_widget_container:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/custom_question_widget_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="vertical"
android:padding="10dp" />
So, the questionWidget seems to have been retaining the parent for almost 4 steps outside visibility, and when I scroll to the opposite direction fast, I would encounter it still with its parent, then I'm attempting to add it to another container.
Here's the fix - option 1:
override fun onBindViewHolder(holder: QuestionWidgetViewHolder, position: Int) {
holder.linearLayoutContainer.removeAllViewsInLayout()
val questionWidget: QuestionWidget =
dataSource[position]
questionWidget.setValueChangedListener(this)
val initialWidgetParent : ViewParent? = questionWidget.parent
//attempt to detach from previous parent if it actually has one
(initialWidgetParent as? ViewGroup)?.removeView(questionWidget)
holder.linearLayoutContainer.addView(questionWidget)
}
Another better solution - option 2:
override fun onBindViewHolder(holder: QuestionWidgetViewHolder, position: Int) {
holder.linearLayoutContainer.removeAllViewsInLayout()
val questionWidget: QuestionWidget =
dataSource[position]
questionWidget.setValueChangedListener(this)
val initialWidgetParent : ViewParent? = questionWidget.parent
//if it's in a parent container already, just ignore adding it to a view, it's already visible
if(initialWidgetParent == null) {
holder.linearLayoutContainer.addView(questionWidget)
}
}
Actually, it's much of asking the child if it has a parent before adding it to a parent.
I tried all the things that you guys suggested, with no luck.
But, I managed to fix it by moving all my binding initializations from onCreate to onCreateView.
onCreate(){
binding = ScreenTicketsBinding.inflate(layoutInflater)
}
MOVE TO
onCreateView(...){
binding = ScreenTicketsBinding.inflate(layoutInflater)
}
You can use this methode to check if a view has children or not .
public static boolean hasChildren(ViewGroup viewGroup) {
return viewGroup.getChildCount() > 0;
}
My case was different the child view already had a parent view i am adding the child view inside parent view to different parent. example code below
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/lineGap"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/black1"
android:layout_gravity="center"
android:gravity="center"
/>
</LinearLayout>
And i was inflating this view and adding to another LinearLayout, then i removed the LinaarLayout from the above layout and its started working
below code fixed the issue:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#color/black1" />
It happened with me when I was using Databinding for Activity and Fragments.
For fragment - in onCreateView we can inflate the layout in traditional way using inflater.
and in onViewCreated method, binding object can be updated as
binding = DataBindingUtil.getBinding<FragmentReceiverBinding>(view) as FragmentReceiverBinding
It solved my issue
In my case, I was doing this (wrong):
...
TextView content = new TextView(context);
for (Quote quote : favQuotes) {
content.setText(quote.content);
...
instead of (good):
...
for (Quote quote : favQuotes) {
TextView content = new TextView(context);
content.setText(quote.content);
...
If you are working with MaterialAlertDialog, this worked for me:
(yourChildView.parent as? ViewGroup)?.removeView(yourChildView)
If in your XML you have layout with id "root" It`s problem, just change id name

android - TextView getting scrollbar to always show programatically

I am dynamiclly creating a View which contains an image and a TextView this is then being added to a ViewFlipper. This is all working as it should the issue is I require the scrollbar to always be visible, however I simple cannot get it to work and am not sure what I am doing wrong.
Below is my dynamic code and the xml code which I am trying to replicate
for(int i = 0; i < 5; i++)
{
// Creating my linear layouts & views
lls = new LinearLayout(this);
llv = new LinearLayout(this);
lls.setOrientation(LinearLayout.VERTICAL);
// Adding image view
imgStory = new ImageView(this);
imgStory.setImageResource(GetImage(i));
imgStory.setLayoutParams(new LayoutParams(width, width));
lls.addView(imgStory);
// adding textview, which is scrollable
txtStory = new TextView(this);
txtStory.setText(unescape(story.get(i)));
txtStory.setTextColor(getResources().getColor(R.color.orange));
txtStory.setPadding((int)padding, (int)padding, (int)padding, (int)padding);
txtStory.setMovementMethod(new ScrollingMovementMethod());
//txtStory.setVerticalScrollBarEnabled(true);
//txtStory.setVerticalFadingEdgeEnabled(false);
lls.addView(txtStory);
// Adding views to my view flipper
llv.addView(lls);
viewFlipper.addView(llv, i);
}
XML code I am trying to replicate programatically
<TextView
android:id="#+id/txtStoryText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/imgStoryLine"
android:layout_above="#+id/footer"
android:layout_margin="20dp"
android:scrollbars="vertical"
android:scrollbarSize="10dp"
android:fadeScrollbars="false"
android:textColor="#color/orange"
android:text="" />
How about trying to use a ScrollView as the top most parent. So, something like this:
// Creating my linear layouts & views
lls = new LinearLayout(this);
llv = new ScrollView(this); // This looks like the view you're adding to the viewFlipper
lls.setOrientation(LinearLayout.VERTICAL);
Or, if it's just the text you want to scroll, make the first LinearLayout a Scrollview:
// Creating my linear layouts & views
lls = new ScrollView(this); // This wraps your textView
llv = new LinearLayout(this);
lls.setOrientation(LinearLayout.VERTICAL);
NOTE: this is not tested. Just trying to give you an idea. You may have to specify more layout parameters for the ScrollView to get this to work.
You can also take a look at this post where they talk about setting:
textView.setMovementMethod(new ScrollingMovementMethod())

Clickable ListView

I'm looking now a few days for a solution for clickable items in a listView.
First I came across this:
developer.android.com/resources/articles/touch-mode.html
and found that it's doesn't have the "normal" onListItemClick() behavouir.
Then I came across of this code:
http://www.androidsnippets.org/snippets/125/
// LINE 296-321
#Override
protected ViewHolder createHolder(View v) {
// createHolder will be called only as long, as the ListView is not filled
// entirely. That is, where we gain our performance:
// We use the relatively costly findViewById() methods and
// bind the view's reference to the holder objects.
TextView text = (TextView) v.findViewById(R.id.listitem_text);
ImageView icon = (ImageView) v.findViewById(R.id.listitem_icon);
ViewHolder mvh = new MyViewHolder(text, icon);
// Additionally, we make some icons clickable
// Mind, that item becomes clickable, when adding a click listener (see API)
// so, it is not necessary to use the android:clickable attribute in XML
icon.setOnClickListener(new ClickableListAdapter.OnClickListener(mvh) {
public void onClick(View v, ViewHolder viewHolder) {
// we toggle the enabled state and also switch the icon
MyViewHolder mvh = (MyViewHolder) viewHolder;
MyData mo = (MyData) mvh.data;
mo.enable = !mo.enable; // toggle
ImageView icon = (ImageView) v;
icon.setImageBitmap(
mo.enable ? ClickableListItemActivity.this.mIconEnabled
: ClickableListItemActivity.this.mIconDisabled);
}
});
While debugging I noticed the parameter View v is a TextView and not a "normal" View and then of course:
TextView text = (TextView) v.findViewById(R.id.listitem_text);
returnes null and I get a NullPointerException...
Any ideas why? And how I can solve this?
Thanks in advance! :)
How do you create your instance of ClickableListAdapter ?
When you create your list adapter, you have to pass a resource id viewId, this should be a layout which will be inflated later.
public ClickableListAdapter(Context context, int viewid, List objects) {
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
mDataObjects = objects;
mViewId = viewid;
Below, the code inflate the xml layout passed to the constructor and call createHolder.
view = mInflater.inflate(mViewId, null);
// call the user's implementation
holder = createHolder(view);
So make sure that when instantiating your ClickableListAdapter, you pass a layout instead of an id
Edit
You have to create a xml layout with the following which is taken from the link you have provided:
<?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="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
>
<TextView android:text="Text" android:id="#+id/listitem_text"
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
></TextView>
<ImageView android:id="#+id/listitem_icon"
android:src="#drawable/globe2_32x32"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="32px"
android:maxHeight="32px"
>
</ImageView>
</LinearLayout>
If you call it mylistrow.xml in the layout directory, so you construct your adapter as :
adapter = new MyClickableChannelListAdapter(this, R.layout.mylistrow, channelList);
setListAdapter(adapter);
List items should be clickable right out of the box. You can check how lists are coded by looking at ApiDemos project code. It should be present on your local machine since it is a part of the SDK. I have it at <root_sdk_folder>\platforms\android-2.0.1\samples\ApiDemos.

Categories