Hellow this is my first question in stack.
Im creating a dynamic grid of this tutorial
http://www.stealthcopter.com/blog/2010/09/android-creating-a-custom-adapter-for-gridview-buttonadapter/comment-page-1/
Now it's working pretty good. My layout is composed by a gridView and under this gridView i have a TextView.
The problem is that i want to change the TextView to display different information on each id when the focus changes (on the grid elements). I've tried to use OnFocusChangeListener inside ButtonAdapter, but when trying to get a reference to the textView, it says that findViewById is not implemented.
I wonder how to make a reference in my main activity that allows me to handle my dynamic grid elements.
I have the following in onCreate();
GridView gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(new ButtonAdapter(this));
So i want to handle my grid elements from here, any ideas?
Thanks
Edit:
I've been trying to change different things, but im receiving a NullPointerException from my getView method. I can't find a way to make it work, i'll apreciate any help guys, this is my code:
public View getView(int position, View convertView, ViewGroup parent) {
final Button btn;
if (convertView == null) {
// if it's not recycled, initialize some attributes
btn = new Button(mContext);
btn.setLayoutParams(new GridView.LayoutParams(100, 55));
btn.setPadding(8, 8, 8, 8);
} else {
btn = (Button) convertView;
}
btn.setText(filenames[position]);
// filenames is an array of strings
btn.setTextColor(Color.WHITE);
btn.setId(position);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
TextView vt = (TextView) btn.findViewById(R.id.textView1);
vt.setText("Button Pressed");
}
});
Thanks.
I think you are on the right track, but I think it would make most sense to take care of it in your adapter. So findViewById() isn't working for you, but it will work if you change it to convertView.findViewById() (or whatever view is returned in your getView method of your Adapter). From there you will be able to manipulate the TextView.
Related
As a little eperiment, I'm trying to do the following.
I have an AXML describing a vertical linear layout which contains a listview (only filling 200dp of the vertical linear layout ). The AXML is inflated when the activity starts with SetContentView. Then the listview is correctly populated with values using its Adapter.
In the GetView method of the listview Adapter, I am trying to also dynamically create a button and add it to the linear layout, but for some reason the button is not added.
If I try to add the button in the constructor method of the Adapter instead, it is correctly added.
Can you tell me what could be possibly going wrong?
Let me add some code:
class TracksAdapter : BaseAdapter<string> {
Activity context;
List<Dictionary<string,string>> trackList;
// constructor
public TracksAdapter (Activity context, List<Dictionary<string,string>> trackList) {
this.context = context;
this.trackList = trackList;
// Just as a little test, if I create the button from here it will be correctly added to linear layout:
var ll = context.FindViewById<LinearLayout>(Resource.Id.linLayForResultsActivity);
Button b1 = new Button(context);
b1.Text = "Btn";
ll.AddView(b1);
}
public override View GetView(int position, View oldView, ViewGroup parent) {
// if I create the button from here it will not be added to the layout
var ll = context.FindViewById<LinearLayout>(Resource.Id.linLayForResultsActivity);
Button b1 = new Button(context);
b1.Text = "Btn";
ll.AddView(b1);
// this other code is working
View view = context.LayoutInflater.Inflate(Resource.Layout.ResultItem, null);
var artistLabel = view.FindViewById<TextView>(Resource.Id.resultArtistNameTextView);
artistLabel.Text = trackList[position]["trackArtistName"];
return view;
}
}
Update: adding some more context information because I know this can be a bit weird to understand without it:
In GetView, I don't need to return the new button I am trying to create there. GetView only need to return a listview view item, but, along its execution, GetView also has to create and add a button to the linear layout containing the listview.
The real code is much more complex than that. I have simplified it in the question. In the real code, the listview items are made of text and a button. The GetView also attaches event handlers to the buttons. Then what I need is, when a user clicks a button in any of the listview items, another button is added below the listview. So I need the code for adding another button to be in GetView, and the button needs to be added outside of the listview, ie. to the linear layout containing the listview.
Use the LayoutInflator to create a view based on your layout template, and then inject it into the view where you need it.
LayoutInflater vi = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = vi.inflate(R.layout.your_layout, null);
// fill in any details dynamically here
TextView textView = (TextView) v.findViewById(R.id.a_text_view);
textView.setText("your text");
// insert into main view
ViewGroup insertPoint = (ViewGroup) findViewById(R.id.insert_point);
insertPoint.addView(v, 0, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
I looked in you code, you are returning view, while you add the button to ll, you should return ll
what you return in getView() is what you see in the list item layout, since you're adding the button to ll and returning view, the button won't appear.
you can add the button to view as you implementation
Also check this:
Try using boolean addViewInLayout (View child, int index, ViewGroup.LayoutParams params)
http://developer.android.com/reference/android/view/ViewGroup.html#addViewInLayout(android.view.View, int, android.view.ViewGroup.LayoutParams)
It's working... Without making any changes now it's working as it should... ! Ugh!
I really don't know what I was doing wrong here... probably it was because of some sort of caching of older version of the installed APK.. ? I know this sort of stuff can happen, and that's why I've always been uninstalling the app before deplyoing the new version to the device... but still...!
I have a base adapter class which i use to fill in a listview. Some of the contents are defined in a layout file and i also need to dynamically add in a certain number of image button depending on the int value passed to the base adapter.
The obj is a object that has the int value along with a arrayList of bitmaps;
when i run this code i get more image buttons then the value of obj.value.
likePre_pics is the name of the arrayList of bitmaps
Can someone please help?
public class News_Feed_BaseAdapter extends BaseAdapter{
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LinearLayout linLayout =
(LinearLayout)convertView.findViewById(R.id.like_preview_LinearLayout);
for(int i=0; i< obj.value;i++)
{
ImageButton op= new ImageButton(context);
LayoutParams lpView = new LayoutParams(100, 100);
//op.setImageBitmap(obj.get(position).likePre_pics.get(i));
linLayout.addView(op,lpView);
}
}
}
As i can see from your code there is two problem,first is IndexOutOfBoundsException. ArrayList IndexOutOfBoundsException only occurs when there is more/less item then you are referring to.
//op.setImageBitmap(obj.get(position).likePre_pics.get(i));
The line you commented out. You are referring to obj.get(position) where obj has obj.size() number of element.
Next is ImageButton issue since you are not reusing the convertview in an efficient way when you are adding new imagebutton into linLayout of convertview that is why linLayout is showing more then 2 imagebutton.
For example: If you have 20 items in your list that means getView will be called 20 times. As you will find in android documentation convertView is the old view that gets passed for you to reuse and every-time it gets passed to you , you are adding more imagebutton into it. That's why imagebutton problems are occurring.
Take a look into Romain Guy's World of ListView google i/o presentation if you are interested.
public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {
// new method
private ListView listView;
private AsyncImageLoader asyncImageLoader;
private ImageAndText imageAndText;
//constructor
public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts) {
super(activity, 0, imageAndTexts);
asyncImageLoader = new AsyncImageLoader();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Activity activity = (Activity) getContext();
////////////////////////////////////////////////////////////////////////////////////////////////
// Load the image and set it on the ImageView
//new method
// Inflate the views from XML
View rowView = convertView;
ViewCache viewCache;
if (rowView == null) {
LayoutInflater inflater = activity.getLayoutInflater();
rowView = inflater.inflate(R.layout.image_and_text_row, null);
viewCache = new ViewCache(rowView);
rowView.setTag(viewCache);
} else {
viewCache = (ViewCache) rowView.getTag();
}
imageAndText = getItem(position);
Button btn2=(Button) findViewById(R.id.button1);
btn2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//...........
}
});
This adapter is for the ListView, and it takes the image_and_text_row.xml which represent the row data of the listview. The program crashed when I set a click listener to the btn2. If the listener is deleted then the program runs fine.
the question is why the adapter cannot have a button click listener inside the code?
Just a shot in the dark: but your line Button btn2=(Button) findViewById(R.id.button1); refers to the ListActivity or ListView that the adapter is in. Therefore, R.id.button1 does not exist...
Have you tried: Button btn2=((Button)rowView.findViewById(R.id.button1)); This may be your issue (without being able to see your logcat, that is). findViewById() finds children. The original statement would look for the child of the Activity or View. This new statement would find the child of the rowView.
Of course, this is an assumption, as since you have not described the application or problem completely, I must assume according to the information that we do have that there is a button for every row.
Hope this helps,
FuzzicalLogic
P.S. Hope you caught the hint that you will get shoddy answers like this one if there is a lack of pertinent information. A good guide is: 1) What is happening? 2) What do you expect to happen? 3) What do your debugging resources indicate? 4) What supplemental research or concepts do we need to know? These lead to longer questions, but they are certainly more effective and so are the answers that result from them.
What you should do is add the onClick to your xml file where the button is.
Also make sure your button is inside the same layout you are inflating.
I have a ListView whose rows are formatted by me. Each row has a mix of ImageView and TextView.
I have also implemented my own adapter and am able to draw each row through it.
Now, I would want something like this-
User clicks on an ImageView (not anywhere else on the row, but only this ImageView should respond to clicks)
I get to know the position of the row whose ImageView was clicked.
I have tried many things for this and have wanted my code to be as efficient as possible (in terms of overkill).
Currently i can capture the click event on that particular ImageView only, but I can't know which row was clicked.
I have provided an attribute in the Row XML like this-
<ImageView android:id="#+id/user_image"
android:padding="5dip"
android:layout_height="60dip"
android:layout_width="60dip"
android:clickable="true"
android:onClick="uImgClickHandler"/>
And in my code, I have a method like this:
public void uImgClickHandler(View v){
Log.d("IMG CLICKED", ""+v.getId());
LinearLayout parentRow = (LinearLayout)v.getParent();
}
I can get the parent row (perhaps) but am not sure how to go further from here.
Can someone please help?
Please refer this,
Me just writing the code to give you idea, Not in correct format
class youaddaper extends BaseAdapter{
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater inflate = LayoutInflater.from(context);
View v = inflate.inflate(id, parent, false);
ImageView imageview = (ImageView) v.findViewById(R.id.imageView);
imageview.setOnClickListener(new imageViewClickListener(position));
//you can pass what ever to this class you want,
//i mean, you can use array(postion) as per the logic you need to implement
}
class imageViewClickListener implements OnClickListener {
int position;
public imageViewClickListener( int pos)
{
this.position = pos;
}
public void onClick(View v) {
{// you can write the code what happens for the that click and
// you will get the selected row index in position
}
}
}
Hope it helped you
Another option is to use the methods setTag() and getTag() of the view. You set it in your getView like this:
imageView.setTag(new Integer(position));
Then in the onClick() you can find the tag by:
Integer tag = v.getTag();
This will then be used to correlate the image view to the position of the listview item.
Note that this approach will give problems if the listview can lose items from the middle, so that the item positions change during the lifetime of the listview.
you can simply do like this:
in the getview method of our adapter
Button btn1 = (Button) convertView.findViewById(R.id.btn1);
btn1.setOnClickListener(mActivity);
further you can handle the onclick event in your activity,,
for the context of the activity here mActivity just pass the this in the constructer of the adapter and cast it here into the activity like
MyActivity mActivity=(MyActivity)context;
in the adapter.
thanx
This appears to work in a ListActivity whose item layout contains an ImageView with android:onClick="editImage":
public void editImage(View v) {
int[] loc = new int[2];
v.getLocationInWindow(loc);
int pos = getListView().pointToPosition(loc[0], loc[1]);
Cursor c = (Cursor) adapter.getItem(pos);
// c now points at the data row corresponding to the clicked row
}
I have an application that will have 5-15 buttons depending on what is available from a backend. How do I define the proper GridView layout files to include an array of buttons that will each have different text and other attributes? Each button will essentially add an item to a cart, so the onClick code will be the same except for the item it adds to the cart.
How can I define an array so I can add a variable number of buttons, but still reference each of them by a unique ID? I've seen examples of the arrays.xml, but they have created an array of strings that are pre-set. I need a way to create an object and not have the text defined in the layout or arrays xml file.
Update - Added info about adding to a GridView
I want to add this to a GridView, so calling the [addView method](http://developer.android.com/reference/android/widget/AdapterView.html#addView(android.view.View,%20int) results in an UnsupportedOperationException. I can do the following:
ImageButton b2 = new ImageButton(getApplicationContext());
b2.setBackgroundResource(R.drawable.img_3);
android.widget.LinearLayout container = (android.widget.LinearLayout) findViewById(R.id.lay);
container.addView(b2);
but that doesn't layout the buttons in a grid like I would like. Can this be done in a GridView?
In the following code, you should change the upper limits of the for to a variable.
public class MainActivity
extends Activity
implements View.OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TableLayout layout = new TableLayout (this);
layout.setLayoutParams( new TableLayout.LayoutParams(4,5) );
layout.setPadding(1,1,1,1);
for (int f=0; f<=13; f++) {
TableRow tr = new TableRow(this);
for (int c=0; c<=9; c++) {
Button b = new Button (this);
b.setText(""+f+c);
b.setTextSize(10.0f);
b.setTextColor(Color.rgb( 100, 200, 200));
b.setOnClickListener(this);
tr.addView(b, 30,30);
} // for
layout.addView(tr);
} // for
super.setContentView(layout);
} // ()
public void onClick(View view) {
((Button) view).setText("*");
((Button) view).setEnabled(false);
}
} // class
Here's a nice sample for you:
https://developer.android.com/guide/topics/ui/layout/gridview.html
You should just create buttons instead of imageviews in getView adapter method.
If you are using a GridView, or a ListView (etc), and are producing Views to populate them via the adapter getView(pos, convertView, viewGroup), you might encounter confusion (i did once).
If you decide to re-use the convertView parameter, you must reset everything inside of it. It is an old view being passed to you by the framework, in order to save the cost of inflating the layout. It is almost never associated with the position it was in the layout before.
class GridAdapter extends BaseAdapter // assigned to your GridView
{
public View getView(int position, View convertView, ViewGroup arg2) {
View view;
if (convertView==null)
{
view = getLayoutInflater().inflate(R.layout.gd_grid_cell, null);
}
else
{
// reusing this view saves inflate cost
// but you really have to restore everything within it to the state you want
view = convertView;
}
return view;
}
// other methods omitted (e.g. getCount, etc)
}
I think this represents one of those Android things where the concept is a little difficult to grasp at first, until you realize there's a significant optimization available within it (have to be nice to CPU on a little mobile device)