So I have been trying to use a canvas with bitmaps to create a grid of clickable images for a game. It is made to be a 19 x 19 board and this would be made of clickable images so that when you click a image it changes to a new image. I have tried doing this and I get the grid of images but I can not figure out a way to make them clickable. I would show code but there is nothing to show really. its just a basic custom view. Maybe I am doing this all wrong but I have seen a way that is somewhat similar that works but it does not use custom images. I can add a onTouchListener and then I get a response back but it still does not fulfill what I am trying to accomplish. I guess I need to create buttons inside of my custom view but I need the buttons to be customized by images and I cant figure out how I would go about doing that. That is where the issue lies, If there is a way to create a custom View of a grid of customizable buttons. How would I go about doing that? Sorry if this question seems.... messy but I have been working at this for awhile now and am getting pretty confused and lost. Any help is appreciated at this point.
Yep, I think so. Not sure but if you use a grid view with image views on them you can do what you want to accomplish. For more in formation, check here:
http://developer.android.com/guide/topics/ui/layout/gridview.html
http://developer.android.com/reference/android/widget/ImageView.html
You could just use a GridFragment and just implement the onGridItemClick method to handle the clicks. It is pretty straight forward.
If you want to have a gridview with buttons with custom background images I would go about it something like this.
I would store all my drawables in an int array
int[] imageResource = new int[] {R.drawable.icon, R.drawable.icon2, R.drawable.icon3};
Set your gridView with the adapter shown below and pass your drawables stored in an array
yourGridView.setAdapter(new GridAdapter(imageResource));
Now for the actual inner class Adapter
//create your own custom adapter for your gridView
public class GridAdapter extends BaseAdapter {
int[] gridImages;
public GridAdapter(int images[]){
gridImages = images;
}
#Override
public View getView(final int position, View convertView,
ViewGroup parent) {
LayoutInflater li = context.getLayoutInflater();
if (convertView == null) {
//here you inflate your xml containing a button.
convertView = li.inflate(R.layout.grid_item, null);
}
//you reference the button contained in the inflated xml
Button imageButton = (Button) convertView.findViewById(R.id.grid_button);
//now you set the button with a drawable from your int array
Drawable image = getResources().getDrawable(gridImages[position);
// Now simply add your onClickListener and whatever else you need to achieve
//return your view
return convertView;
}
public int getCount() {
return gridImages.length;
}
public Object getItem(int position) {
return gridImages[position];
}
public long getItemId(int position) {
return position;
}
}
If done correctly, this should cycle through all your drawables referenced in the int array and place them on to buttons.
Related
I'm trying to make an activity able to capture up to 4 images for sending them to our server.
I know how to capture the image and to add them to the activity, this already works, in a non efficient nor elegant way, and I would like to improve that.
Right now, I have Button with an onClick method that attaches an image to an empty ImageView, and and keeps track of how many images have been attached, because I can delete an image in order to pick a new one.
I'm wondering the best strategy, code-wise for future changes.
Options that I have considered but I have not (yet) implemented:
Button adds the image to a GridView so I can add and remove images from it's adapter instead.
The ImageView can attach and remove image from itself by onClick and therefore remove the Button
Any suggestions, ideas, strategies, thoughts?
Thank you in advance!
EDIT 1: my first approach to improve the code
I've implemented a GridView with a custom adapter (GridImageAdapter)
public class GridImagesAdapter extends BaseAdapter{
private List<Bitmap> images = new ArrayList<Bitmap>();
private int img_height;
public GridImagesAdapter(Context context, List<Bitmap> imagenes){
this.imagenes = imagenes;
inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
img_height = (int) (metrics.density * Constants.ONE_ROW_IMG_HEIGHT);
}
/*
* other common methods
*/
#Override
public View getView(int position, View row, ViewGroup parent) {
ViewHolder holder;
if(row == null){
row = inflater.inflate(R.layout.grid_img_item, parent, false);
holder = new ViewHolder();
holder.image = (ImageView) row.findViewById(R.id.img_add_in_grid);
holder.image.setLayoutParams(new GridView.LayoutParams(LayoutParams.MATCH_PARENT, img_height));
holder.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
}else{
holder = (ViewHolder)row.getTag();
}
holder.image.setImageBitmap(getItem(position));
row.setTag(holder);
return row;
}
private class ViewHolder{
ImageView image;
}
}
So I can populate my GridView in the activity like:
private void populateGridView(){
Bitmap a;
a = BitmapFactory.decodeResource(getResources(), R.drawable.no_image);
images.add(a);
images.add(a);
images.add(a);
images.add(a);
GridImagesAdapter adapter = new GridImagesAdapter(this, images);
mGridView.setAdapter(adapter);
mGridView.setOnItemClickListener(new GetImage());
}
where new GetImage() is an OnItemClickListener who takes care of the image capture itself, and replaces one of the R.drawable.no_image Bitmap
(no relevant code in there, just showing a Dialog to the user in order to choose from camera or gallery and start such Activity, and then in the onActivityResult method where I have a Bitmap to work with is where I handle the adapter change)
My question is more about the strategy chosen here than the actual code itself.
Drawbacks? Any more elegant or proper way to achieve the same result?
Everything is welcome, thank you for your answers.
Have u create a gridview and set up the adapter class?
Because I have implemented a similar case. Items are added to listview dynamically (by user input), and there is a button in each row that deletes that particular row (also from the database).
If u have, Let me know from where shall we begin.
Your general idea is more or less correct. You mentioned GetImage is irrelevant, but it absolutely isn't. From I understood, you are changing the view directly in there. Instead you should manipulate the adapter, changing the data it's holding, and then call notifyDataSetChanged. The adapter will take care of notifying the gridview that the data changed and the view will be updated. I would probably use an ArrayAdapter instead of a BaseAdapter as well.
I'm new to Android programing. I need to create a list of 1000 goods for users to click and check or the one they want to buy. I've created the array list and added it to my custom adapter and I have also added it to my list view. my problem is how to get the position for each item selected and I need clarification on the getView and the ViewHolder. I'm not working with toast
See the below tutorials,
http://sunil-android.blogspot.in/2013/04/android-listview-checkbox-example.html
http://developerandro.blogspot.in/2013/09/listview-with-checkbox-android-example.html
http://aboutyusata.blogspot.in/2013/11/how-to-make-listview-with-checkbox-in.html
Hope it helps.
You have to use ListView getCheckedItemPositions()
/**
* Returns the set of checked items in the list. The result is only valid if
* the choice mode has not been set to {#link #CHOICE_MODE_NONE}.
*
* #return A SparseBooleanArray which will return true for each call to
* get(int position) where position is a checked position in the
* list and false otherwise, or <code>null</code> if the choice
* mode is set to {#link #CHOICE_MODE_NONE}.
*/
public SparseBooleanArray getCheckedItemPositions() {
if (mChoiceMode != CHOICE_MODE_NONE) {
return mCheckStates;
}
return null;
}
getView() method is called when new list item that is adapted is being shown on your screen. That is why you need to take good care of the memory and setTag() for every item you inflate. Then when old item is viewed again you will not render it like a new one but get it by the tag you submitted for that item.
Example: If you have 1000 items only couple of those will be shown on the screen and your program will call getView() for those items that are visible plus for couple of items bellow those that are visible so you don't see the lag in inflation while scrolling.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(view==null)
{
LayoutInflater inflater=getLayoutInflater();
view=inflater.inflate(R.layout.list, parent, false);
TextView textView=(TextView)view.findViewById(R.id.text_hint);
ImageView imageView=(ImageView)view.findViewById(R.id.img);
// here we will setTag() our view later
}
//... (here we will manage the views and set some click listeners)
Now, what is a viewHolder?
The ViewHolder basically is the private class inside your adapter that is used to keep you inflated layout elements together and to let you manipulate those view after you got the using findViewById(int resId).
Some code:
private class ViewHolder{
public ImageView imageView;
public TextView textView;
public ViewHolder(ImageView imageView,TextView textView) {
this.imageView = imageView;
this.textView = textView;
}
}
Now to setTag() as promised.
view.setTag(new Holder(imageView,textView));
Now with this in mind you can get your ViewHolder using the code above and views that you got in the first part of my code. (this is what we will write instead of 3 dots)
ViewHolder h = (Holder) view.getTag();
h.textView.setText(ar[position]);
int resID = getResources().getIdentifier(pic[position], "drawable", getPackageName());
h.imageView.setImageResource(resID);
// here I did set some source to my imageView that is in my layout, but
// you can do whatever you want with these views. And that is what I'm
// going to explain later in this text.
return view;
}
Okay, what next?
After getting the ViewHolder from tag you have your entire layout as a View that can get his OnClickListener easily. Or just a checkBox can get OnCheckedChangeListener.
Inside methods for this listeners you can send the data to you controller (in case you are using MVC model) or to your activity that hosts this View, where you can save the state of the checkbox and title of the item that has been clicked.
For example you can do something like this on your corresponding listener method:
(MainActivity)context.markAsChecked(String title);
But in this case you will also need to have the opposite method for unchecking
(MainActivity)context.markAsUnchecked(String title);
and you will have to handle this in your MainActivity properly by browsing through the array of data that has been selected.
The second solution is to have :
(MainActivity)context.toggleState(String title);
And to handle both events checked and unchecked.
Your method in your Activity would need to do something similar to this:
public void toggleState(String title){
if (data.contains(title))
data.remove(title);
else data.add(title);
}
Then after your user checks what he wants you will have all the checked elements in your data array that in this case is ArrayList. You can also you HashMap for this if you like or something else too.
Hope this helps.
I will be more than happy to answer all of your questions if have some more.
Maybe controller implementation is something that you would like to consider in this case. That would mean that you would be using MVC model for better control of your app and data, and to delegate the tasks to responsible classes and methods. Not to put everything in one Activity :)
Bye
I have a ListView and posibility to select one element (single choice).
How can I set background color for all elements of ListView (maybe which are visible at least) when some item was selected?
adapter = new ArrayAdapter<Orderline>(activity, simple_list_item_single_choice, orderlines) {
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
...
convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
convertView.setBackgroundColor(BLACK);
// so here currently selected element is set to BLACK, but also other elements have to be set to WHITE
}
});
return convertView;
}
}
I don't have much code for you because I'm not at my workstation right now, but I'm thinking you can just set the background of the selected item to black by via your onItemClick as you've already suggested. Cool.
To change the color of the other(unselected) views when a particular view is selected, I'm guessing you can call your Adapter's getCount() and loop through that list, make a call to getChildAt(i) of your ListView. This returns a View which you can call setBackgroundColor(Color) on. Hope this helps
You can do
parent.setBackgroundColor(BLACK);
this.notifyDataSetChanged();
to set your list view background.
I would use a Drawable selector.
Check this link for a pretty good example:
http://www.charlesharley.com/2012/programming/custom-drawable-states-in-android/
Basically you create the XML drawable which contains a mapping (which the system uses automatically) to what you would like displayed when certain click events occur.
You can assign the background drawable to any view, so you could do it in your XML for your adapter, or in Java code. Which in your case might be something like this:
convertView.setBackgroundDrawable(R.drawable.MySelector);
parent.setBackgroundColor(while_color);
v.setBackgroundColor(black_color)
I have a GridView adapter based on some example code that I'm trying to figure out. Basically I have an arraylist of applications that I pass into the adapter, the Applications class, among other things, contains the packageinfo for all apps that have been qualified by the user as "Arcade". What I want is to extract the icons from the packageinfo then blow them up and put them into the GridView, no text or anything else underneath, just the app icons.
public class GridAdapter extends BaseAdapter {
private Context mContext;
ArrayList<Applications> mlistArcadeApps;
public GridAdapter(Context context, ArrayList<Applications> listArcadeApps) {
this.mlistArcadeApps = listArcadeApps;
mContext = context;
}
public int getCount() {
return mlistArcadeApps.size();
}
public Object getItem(int position) {
return mlistArcadeApps.get(position);
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView =
}
}
I have that much so far, I'm not entirely sure if this is even right, I'm just trying to get a hold on how to use GridViews, is it possible to extract app icons as an ImageView object? Or is there an alternative method I should look at?
Yes you are doing it right, you need to create another XML file for each item in the list. Create and XML file and put ImageView inside the LinearLayout. After that you need to pass this xml file to your GridView.
Inside your getView method you can update ImageView and show your icons.
This tutorial explains it clearly : Android GridView Layout Tutorial
I just realized, in this tutorial he doesn't create XML file for each item, instead he creates new ImageView at RunTime.
If you look at this example, it shows in different way : Android GridView Example
I am working on customize (inflated) list view. In which I have used the text and background image for text (as per the condition).
Now I am facing problem in scrolling the list view that background of text view is overlapping to the other text views.
Here is the sample code:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View icontextlayout=convertView;
icontextlayout= inflater.inflate(R.layout.layout_complex_list, null);
TextView Txt1=(TextView)icontextlayout.findViewById(R.id.txt1);
if(disp1==true)
{
Txt1.setBackgroundResource(R.drawable.pic)
}
else
Txt1.setText("Text1 "+strUser);//
TextView Txt2=(TextView)icontextlayout.findViewById(R.id.txt2);
if(disp2==true)
{
Txt2.setBackgroundResource(R.drawable.pic);
}
else Txt2.setText("Text2: "+strIndus);
return icontextlayout;
}
Could you please help me out that background image pic do not overlap the others background.
Thanking you...
The problem is that you must set a default background when you don't need a background. For instance:
if(disp1==true){
Txt1.setBackgroundResource(R.drawable.pic);
Txt1.setText("");
}
else{
Txt1.setText("Text1 "+strUser);//
Txt1.setBackgroundDrawable(null);
}
Also, if you don't mind, I like to give you my opinion about your code:
That's not they way in which list are usually populated. Take a look at this answer: How to load the Listview "smoothly" in android
convertView is used to reuse rows. In your case you are doing something like:
View icontextlayout=convertView;
icontextlayout= inflater.inflate(R.layout.layout_complex_list, null);
Which is bad, because you are not actually using the convertView (when you call inflater.inflate) it will create a new row, thus your list will be really slow.
if(disp2==true) is redundant. You should consider using just: if(disp2).