Is it possible to set the backgroundResource and backgroundColor of a ListView/ExpandableListView in a custom adapter.
I have a transparent png that will serve as the border for each row in an expandable listview. This image is just an inner shadow and a border on the bottom.
The goal is to do something like this:
When I set the backgroundResource and then backgroundColor, only one of the two shows up. I can't get the resource to overlay the color. Does anyone know if this is possible?
Here is my code to get a better idea:
private int[] colors2= new int[] { Color.parseColor("#e2e8e9"), Color.parseColor("#f1f2f2") };
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
ViewHolder holder;
ExpandListGroup group = (ExpandListGroup) getGroup(groupPosition);
if (convertView == null) {
holder = new ViewHolder();
LayoutInflater inf = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
convertView = inf.inflate(R.layout.expandlist_group_item, null);
holder.title = (TextView) convertView.findViewById(R.id.tvGroup);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
int colorPos = groupPosition % colors.length;
convertView.setBackgroundResource(R.drawable.row_forground);
convertView.setBackgroundColor(color2[colorPos]);
holder.title.setText(group.getName());
return convertView;
}
setBackgroundResource and setBackgroundColor both use the same api setBackgroundDrawable internally to do their tasks. So one overwrites the other. So you wont be able to achieve your goal using this api.
You will have to use setBackgroundResource with a custom drawable
If you want to use setBackgroundResource and setBackgroundColor you can do this:
...
int colorPos = groupPosition % colors.length;
convertView.setBackgroundResource(R.drawable.row_forground);
GradientDrawable drawable = (GradientDrawable) convertView.getBackground();
drawable.setColor(color2[colorPos]);
...
There is for sure code which can take background drawable and use paint some color on it. But I can't rember now :-)
But there is other ways how can you achieve your goal. Look at this site:
http://developer.android.com/guide/topics/resources/drawable-resource.html
Look at 9patch drawables which you can prepare, which will be only small images which will shrink/expand as needed. You prepare one with and other color inside.
The second way is to use ShapeDrawable. In XML you create rectangle and some solid color inside it.
In both cases you just swap background drawables as needed.
I don't understand what you want exactly achieve, but I hope that this can help.
Just add a ColorFilter after setting your background ressource to the view like this
view.setBackgroundResource(R.drawable.yourRessource);
view.getBackground().setColorFilter(
Color.yourColor,
PorterDuff.Mode.DST_OVER
);
Learn more about Manipulating images and Drawables with Android’s ColorFilter
Related
I have a few buttons in my app layout, and I want to change the color of those buttons dynamically. When I use
b.setBackgroundColor(0xFF386F00);
the color changes as expected, but the shape, size and padding of the button changes too, like in this related question.
I tried to use the solution suggested in that answer, but doing
b.getBackground().setColorFilter(0xFFFF0000,PorterDuff.Mode.MULTIPLY);
has no effect on any of my buttons. I have no idea what could be the reason for this. The relevant code is this:
import android.widget.Button;
...
#Override
public View getView(int i, View convertView, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.hrlistitems, parent, false);
Button b = (Button) rowView.findViewById(R.id.HRlistB);
b.setOnClickListener(onBButtonClicked);
b.getBackground().setColorFilter(0xFFFF0000,PorterDuff.Mode.MULTIPLY);
rowView.setTag(values.get(i).getId());
TextView textView = (TextView) rowView.findViewById(R.id.HRlisttext);
textView.setText(values.get(i).toTitle());
return rowView;
}
This is part of a custom adapter, which might complicate matters, but I also tried everything I tried on a "normal" button as well, without positive results. Also everything else in the adapter does exactly what I would expect.
This is the button part of the corresponding xml file
<Button
android:id="#+id/HRlistB"
android:layout_width="30dp"
android:layout_height="40dp"
android:layout_above="#+id/HRlist4"
android:layout_toLeftOf="#+id/HRlistB2"
android:layout_toStartOf="#+id/HRlistB3"/>
This button is for some reason rendered as a small square (!), with some space around it, and the corners are rounded. I don't know why that is, but I was quite happy with the way it looks. If setting the background color, the size changes to actual 30dpx40dp, without any padding, and no rounded corners. I am trying to find a way to just change the color and leave the rest as it is.
Why is the ColorFilter not working?
How can I color my button without changing anything else about this button (like size etc.) as a side effect?
You haven't set the filtered drawable as the button's background:
#Override
public View getView(int i, View convertView, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.hrlistitems, parent, false);
Button b = (Button) rowView.findViewById(R.id.HRlistB);
b.setOnClickListener(onBButtonClicked);
Drawable buttonBackground = b.getBackground();
if(buttonBackground != null) {
buttonBackground.setColorFilter(0xFFFF0000,PorterDuff.Mode.MULTIPLY);
b.setBackground(buttonBackground);
}
return rowView;
}
But, if I can be honest, I don't understand the first part of your question:
the color changes as expected, but the shape, size and padding of the button changes too
I think that your problem is that you are using an AppCompat theme so Button is changed to AppCompatButton.
In this case you have to use the setBackgroundTintList(ColorStateList tint) method if you want to achieve that result.
Official documentation can be found here
EDIT
I see now that your button doesn't have a background, you can't use a ColorFilter to change it since the Drawable is null.
I created a ExpandableListView programmatically and I'm using TextView for the groupitems. I now get a problem with the groupIndicator which propably doesn't occur when the ExpandableListView is declared within a xml : The indicator is drawn directly to top of the groupItem ("no paddingTop"). I'm using padding on my TextViews so it looks like the indicator is not aligned to the TextView in height. How can I align the indicator correctly?
Thx
EDIT:
within my custom BaseExpandableListAdapter:
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
Context c = context.get();
if(c==null)
return null;
if(convertView==null){
convertView = new TextView(c);
TextView t = (TextView) convertView;
t.setText(groupData.get(groupPosition));
t.setPadding(left, groupPadding, left, groupPadding); // left '=' android.R.attr.expandableListPreferredItemPaddingLeft
t.setTextSize(TypedValue.COMPLEX_UNIT_PX, groupTextSize);
t.setTextColor(Color.WHITE);
return t;
}
TextView t = (TextView) convertView;
t.setText(groupData.get(groupPosition));
return t;
}
This is a screenshot of one unexpanded groupItem :
As you can see the indicator drawable touches the top-edge of the groupItem.
EDIT2:
I set a custom Drawable as indicator in the hope that it will fix my problem. At first my drawable was stretched to fit groupItem's height. I'm now using 9patchs which prevent the indicator from getting stretched, but this cause the indicator to be aligned to the bottom (instead of to the top as before). Well, still the same problem just reversed. Any ideas how I can fix the problem using my custom drawable? Maybe there is a way to add padding to the indicator (because I know the drawable height and the groupItem's height)?
//indicator_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_expanded="true" android:drawable="#drawable/arrow_right" />
<item android:drawable="#drawable/arrow_down" />
</selector>
//in MainActivity.onCreate()
expView = new ExpandableListView(context);
indicator = context.getResources().getDrawable(R.drawable.indicator_selector);
expView.setGroupIndicator(indicator);
expView.setIndicatorBounds(expView.getPaddingLeft(), expView.getPaddingLeft()+indicator.getIntrinsicWidth());
According to this question and the answer of coderat I figured out how to solve my problem using 9patches [ ExpandableListView - group indication is stretch to fit the text size ] :
I have an adapter to a ListView is a list of ImageViews. I am using a stretch to make the image fil the imageview so I can take smaller images and make them larger on the screen, however the ImageView normally just uses wrap_content and this is an issue because the images just show up as their normal width and height. Is there any way I can set the height and width of a view before drawing it because as in this case I do not have control over the view after it has been drawn. Here is my aapter method:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String currentImage = getItem(position);
ScaleType scaleType = ScaleType.FIT_CENTER;
float screenWidth = parent.getResources().getDisplayMetrics().widthPixels;
if (convertView == null) {
convertView = new ImageView(parent.getContext());
}
// WHAT I WOULD LIKE TO BE ABLE TO DO, but this returns null pointer exception
// convertView.getLayoutParams().width = (int) screenWidth;
// convertView.getLayoutParams().height = (int) ((float)(screenWidth/currentImage.getWidth())*currentImage.getHeight());
((ImageView) convertView).setScaleType(scaleType);
((ImageView) convertView).setImageBitmap(MainActivity.cache.getBitmap(currentImage));
return convertView;
}
How about something like someView.setHeight() and someView.setWidth()? Or someView.setLayoutParams()? You could add either of these to the overridden getView() callback and it should take care of your problem.
You could also Create a Custom View and override something like getMeasuredWidthAndState(). (I think that's one of the right methods, but I'm not one hundred percent sure.) You could create a width class variable and a height class variable that all instances of your custom ImageView would use. However, that might be a bit much if you just want to set the layout width and height though.
I have an Android astronomy app where I need to tint the UI reddish for use at night. Although I have a scheme that works well for many (most??) UI elements, I'm having trouble with the CompoundButtons: CheckBox and RadioButton.
The basic idea is to retrieve the Drawable for the UI element and if it has one to set a color filter on it. My problem is finding the appropriate Drawable for the compound buttons. I would think that getCompoundDrawables() would be what I'd need, but the returned array for the 4 drawables always contains nulls for the 4 elements.
Here is the recursive code I call on the top level view to try to colorize the UI elements.
public static void setNightVisionBkg( View view )
{
if ( view instanceof ViewGroup )
{
Drawable drawable = view.getBackground();
if ( drawable != null )
drawable.setColorFilter( 0xFFAA0000, PorterDuff.Mode.MULTIPLY );
ViewGroup group = (ViewGroup) view;
int numChildren = group.getChildCount();
for ( int i = 0; i < numChildren; i++ )
{
View v = group.getChildAt( i );
Drawable d = v.getBackground();
if ( d != null )
d.setColorFilter( 0xFFAA0000, PorterDuff.Mode.MULTIPLY );
if ( v instanceof ViewGroup )
{
setNightVisionBkg( (ViewGroup) v );
}
else if (v instanceof CompoundButton)
{
CompoundButton compBtn = (CompoundButton)v;
Drawable drawables[] = compBtn.getCompoundDrawables();
for (int j = 0; j < drawables.length; j++)
if (drawables[j] != null)
{
drawables[j].setColorFilter( 0xFFAA0000, PorterDuff.Mode.MULTIPLY );
}
}
}
}
}
Note that it is the latter part where it is getting the Drawables for the CompoundButton that fails to work (all drawables are null).
Any thoughts on how to do this? I know I could set my own custom drawables, but I'd prefer to use the standard ones and just set a colorFilter if possible.
I solved my problem in a slightly different way. Ended up subclassing CheckBox (and RadioButton). In the subclass I override:
protected boolean verifyDrawable( Drawable drawable )
and in this method I set the colorFilter on the drawable. Works great.
You don't progress "normal" non-ViewGroup Views. Furthermore your testing
for ViewGroup in a for loop which can ONLY be ran if the view is a ViewGroup.
I have a gallery feeded by custom adapter using custom views as elements. I need these elements to be scaled by 70% by default. The problem is that gallery behaves like they are at 100% size with 30% transparent padding = spacing between elements are just big. For better understanding I attached two images with elements scaled to 100% and 70%.
Elements scaled to 100%
Elements scaled to 70%
I cannot hardcode the setSpacing as this would behave weird on different resolutions. I tried setSpacing(0) with no luck. How can I achieve that gallery would behave like the elements are small (70%) and not the original size?
I'm scaling the elements by adding setScaleX/Y to the constructor of custom element MagazineCell which extends RelativeLayout:
public MagazineCell(Context context) {
super(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (RelativeLayout) inflater.inflate(R.layout.mag_big, null);
addView(layout);
this.setScaleX(0.7f);
this.setScaleY(0.7f);
}
I also tried to set the scale in drawChild() of the gallery with no luck. In adapter I'm simply using this class for gallery elements:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MagazineCell cell;
position = getPosition(position);
if (null == convertView || convertView.getClass() != MagazineCell.class) {
cell = new MagazineCell(context);
} else {
cell = (MagazineCell) convertView;
}
return cell;
}
Gallery has no special code. I'm using SDK 11 on Acer Iconia TAB A500 running Android 3.1.
Thanks for any hints or comments.
Looks like there's no way to "trick" Gallery to measure scaled cells with their scaled width. So I just used negative spacing - setSpacing(-100); There may be a way via overriding onMeasure method on MagazineCell class and calculate scaled width. But I didn't try this.
after
this.setScaleX(0.7f);
this.setScaleY(0.7f);
add
this.setPivotX(0);
this.setPivotY(0);