Android drawSelectorOnTop with GridView - java

I am developing a tabbed application in which one of the fragments, CollectionsFragment, contains a GridView with an ImageView in each slot. I would like the to use a selector to give feedback to users when the user clicks on one of the images.
I have successfully implemented the selector, however, my problem is that the selector is only drawing in the background of the image, but I would like to the selector to draw over the entire image. I have seen this problem referenced elsewhere, however, the solution selected by many, setting the drawSelectorOnTop property of the GridView, is not working for me.
The relevant fragment with the relevant adapter code:
public class CollectionsFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_collections, container, false);
// Grid view is inside the xml view inflated above
GridView gridView = (GridView)view.findViewById(R.id.gridview);
gridView.setDrawSelectorOnTop(true);
((GridView) gridView).setAdapter(new CustomGridViewAdapter(getActivity()));
return view;
}
private class CustomGridViewAdapter extends BaseAdapter {
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
View v = view;
ImageView picture;
TextView name;
if(v == null) {
v = inflater.inflate(R.layout.collections_item, viewGroup, false);
v.setTag(R.id.picture, v.findViewById(R.id.picture));
v.setTag(R.id.text, v.findViewById(R.id.text));
}
picture = (ImageView)v.getTag(R.id.picture);
name = (TextView)v.getTag(R.id.text);
Item item = (Item)getItem(i);
name.setText(item.name);
picture.setImageResource(item.drawableId);
picture.setBackgroundResource(R.drawable.selector);
return v;
}
}
}
And my selector for completeness sake:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="#color/buttonhighlight"/> <!-- pressed state -->
<item android:state_focused="true"
android:drawable="#color/buttonhighlight"/> <!-- focused state -->
<item android:drawable="#android:color/transparent"/> <!-- default state -->
</selector>
Thanks for any help,

I think you are mistaken about setDrawSelectorOnTop(boolean). The selector drawable that is being referenced here is GridView's internal selector drawable.
Even in the simplest implementation of GridView, when a grid item is clicked, the blue border is drawn around it. This is because, by default, gridview's own selector is drawn behind the item. If you call setDrawSelectorOnTop(true), the selector (blue) will be drawn over the item.
But setDrawSelectorOnTop(boolean) has nothing to do with the selector you are setting in the adapter. Whether you pass true, or false, the ImageView's selector's behavior won't change.
Solution:
Instead of setting the selector on each ImageView inside the adapter, make the GridView use your selector drawable:
GridView gridView = (GridView)view.findViewById(R.id.gridview);
gridView.setDrawSelectorOnTop(true);
// Make GridView use your custom selector drawable
gridView.setSelector(getResources().getDrawable(R.drawable.selector));
Now, there's no need for:
picture.setBackgroundResource(R.drawable.selector);
Edit:
Although I don't recommend this (obvious overhead), it should work:
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
View v = view;
ImageView picture;
....
....
LayerDrawable ld = new LayerDrawable(new Drawable[]
// Drawable from item
{ getResources().getDrawable(item.drawableId),
// Selector
getResources().getDrawable(R.drawable.selector)});
// Set the LayerDrawable
picture.setImageDrawable(ld);
// Don't need this
// picture.setBackgroundResource(R.drawable.selector);
return v;
}

Try setting the xml attribute android:drawSelectorOnTop in your activity_collections.xml file.
See if placing gridView.setDrawSelectorOnTop(true); after gridView.setAdapter(); helps. Sometimes, the order matters (weird).
If all else fails, you may have to switch GridView to some other view where setDrawSelectorOnTop() is proven to work consistently.

Related

Android: How to code layoutAnimation instead of xml

I'm going to give layout animation to item of ListView, which I used android:layoutAnimation before.
<LinearLayout
...
android:layoutAnimation="#anim/layout_anim" />
// ../res/anim
<layoutAnimation
xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="#anim/slide_up" />
I tried to give following codes in adapter.
public View getView(int position, View convertView, ViewGroup parent) {
...
Animation animation = AnimationUtils.loadAnimation(context, R.anim.slide_up);
v.startAnimation(animation);
return v;
}
And it works but the slide_up animation is implemented by full activity's level, not the item level. It appears from bottom of the activity. Originally it should appear from the bottom of item.
What was I wrong?
I solved using LayoutAnimationController.
LinearLayout layout = (LinearLayout) lineView.findViewById(R.id.linearLayout);
LayoutAnimationController anim = AnimationUtils.loadLayoutAnimation(context, R.anim.layout_anim);
layout.setLayoutAnimation(anim);

Android: Gridview Items and making changes to individual items

I'm building an app similar to instagram just for training purposes and basically I have a list of images that I populate through a grid view adapter. In my XML file for 'single_list_item' I have defined a button to be added along with the image for each single item on the grid view list.
However, I want to be able to click on these buttons to 'place a like' on these images separately (similar to instagram's like system). In other words: a user could place a like on the first image and not like the rest of the images. I display a like using a different image resource.
Images get populated by the grid view
Each image has a Like button beneath it
I click on a random like button belonging to a specific image
that image should be selected as 'liked'
What I tried so far:
My grid adapter:
public class ProductGridInflator extends ArrayAdapter<Product>{
.......
.......
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View child = convertView;
final RecordHolder holder;
LayoutInflater inflater = ((Activity) ctx).getLayoutInflater();
if (child == null) {
child = inflater.inflate(R.layout.grid_single, parent, false);
holder = new RecordHolder();
holder.productName = (TextView) child.findViewById(R.id.grid_text);
holder.image = (ImageView) child.findViewById(R.id.grid_image);
holder.heartButton = (ImageButton) child.findViewById(R.id.btnHeartLike);
holder.heartButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (v.isSelected()){
v.setSelected(false);
} else {
holder.heartButton.setSelected(false);
v.setSelected(true);
}
}
});
child.setTag(holder);
}else{
holder = (RecordHolder) child.getTag();
}
}
}
And I'm selecting the appropriate image from a selector (Liked or unliked)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/heart_clicked" android:state_selected="true"/>
<item android:drawable="#drawable/heart304"/>
</selector>
However this code is misbehaving when I test it. When I click on the like button of a specific image list item, two or three other list item's like buttons get clicked as well. Is there a better way to get this done? Individual buttons for each list item?
THe Problem is that you are reusing the onclicklisteners .. Remove this from your getView
holder.heartButton.setOnClickListener(new OnClickListener() {
And instead write in your activity
YouGridView.setOnItemClickListener
And add what you want to do when an item is clicked.

view.getParent() does not return a LinearLayout

I'm trying to make my first Android application, and I want to drag and drop coins into boxes. The onDrag method I found was this:
#Override
public boolean onDrag(View v, DragEvent e) { // onDrag(waarnaartoe, event)
if (e.getAction()==DragEvent.ACTION_DROP) {
// user interface
View view = (View) e.getLocalState();
ViewGroup from = (ViewGroup) view.getParent();
from.removeView(view);
FrameLayout to = (FrameLayout) v;
to.addView(view);
view.setVisibility(View.VISIBLE);
}
return true;
}
The boxes are LinearLayouts, so I changed the original code i.e.
from
ViewGroup from = (ViewGroup) view.getParent(); (which works fine)
to
LinearLayout from = (LinearLayout) view.getParent();
However, the app crashes if I try to drop something onto a box. The reason I want to get the LinearLayout is that I made a Map which connects LinearLayouts to "boxes" (which are theoretical objects with certain properties).
Could anyone explain to me why I cannot replace ViewGroup by LinearLayout?
The function which I copied was not applicable to my program. The line
FrameLayout from = (FrameLayout) e.getLocalState();
works perfectly fine, so e.getLocalstate already gave the container I wanted. Therefore the parent obtained by view.getParent() was the GridLayout.

ListView is empty/disapears after Orientation Change even if Adapter contains Items

I got a ListView with a custom Adapter.
In the Adapter a layout is inflated from xml.
All works fine, and I can see the items, until the Screen Orientation is changed.
I know that the Activity is recreated (or resumed) then, and the ListView is recreated too, as well as the Adapter.
But there are no items in the ListView now. The Adapter isn't empty, I use toasts to display the count of items in the Adapter.
I guess there is an inflating problem, because if I use the same Adapter (or an adapter with the same data) to a new ListView nothing is shown as well.
But the most crazy thing I don't understand is, that if I let my getView() method return a simple TextView, all works fine, even after orientation change.
I tried several things, like don't recycle a View so that it is inflated every time, or save the View to the matching Item (from getItem(position) from the Adapter).
I'm grateful for all hints :)
EDIT: so I was asked for some code.
Here is the getView() of my Adaptar
#Override
public View getView(final int position, View convertView,
ViewGroup parent) {
View view = convertView;
final Event event = getItem(position);
if (view == null) {
view = inflater.inflate(R.layout.new_event_item_layout, parent,
false);
view.setTag(R.id.eventDate, view.findViewById(R.id.eventDate));
view.setTag(R.id.eventTime, view.findViewById(R.id.eventTime));
view.setTag(R.id.eventName, view.findViewById(R.id.eventName));
view.setTag(R.id.eventBemerkungen,
view.findViewById(R.id.eventBemerkungen));
view.setTag(R.id.eventIcon, view.findViewById(R.id.eventIcon));
}
((TextView) view.getTag(R.id.eventDate)).setText(event.getDate());
((TextView) view.getTag(R.id.eventTime)).setText(event.getName());
((TextView) view.getTag(R.id.eventName)).setText(event.getTime());
((TextView) view.getTag(R.id.eventBemerkungen)).setText(event
.getDescription());
SquaredImageView icon = (SquaredImageView) view.getTag(R.id.eventIcon);
Picasso.with(context).load(event.getUri())
.placeholder(R.drawable.ic_reload).into(icon);
view.setBackgroundColor(event.getBackgroundColor());
view.setVisibility(View.VISIBLE);
return view;
//return getDummyTextView();
}
public TextView getDummyTextView()
{
TextView tv=new TextView(context);
tv.setText("YOLO BIATCHSES");
tv.setTextColor(Color.WHITE);
return tv;
}
I have had the same exact problem although it wasn't because of orientation change and I found the solution by just setting listView.setAdapter(adapter) again after the recreation of the activity or whatever case you have. I suspect the listview is basically losing the pointer to the adapter.

SimonVT menudrawer

I have an app that already many activities and class. Like Profile, Friends, Photos, News Feed, etc. I want to integrate that sliding drawer into my main activities. in the examples, they are just showing array list which is implement onClick. so my question is how to change that array list to become my activities like friends, profile, home and etc.
You can use ListView with custom adapter. to adjust custom adapter you can link in your listView that adapter. and in adapter you can put custom icon
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflator = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflator.inflate(R.layout.row, parent, false);
ImageView icon = (ImageView) rowView.findViewById(R.id.row_icon);
TextView title = (TextView) rowView.findViewById(R.id.row_title);
title.setText(proMenu[position]);
String s = proMenu[position];
if(s.equalsIgnoreCase("Home")){
icon.setImageResource(R.drawable.icon_home);
}
else
if(s.equalsIgnoreCase("Best Nearby")){
icon.setImageResource(R.drawable.specialss);
}

Categories