How can I grey out one of my list item entirely, I dont mean set background to grey or sth. else.
public View getView(Context context)
{
View view = _inflater.inflate(R.layout.transfer_item, null);
view.setBackgroundColor(_unmoveable ? 0xFF111111 : Color.TRANSPARENT);
//view.setAlpha(0.5f);//? it says method did not exist ...
put a View into the row on top of everything else and set that View to your grey color.
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 have a custom view which is basically a circle that is either drawn with a fill paint or a stroke paint depending on a column from a database, thus making a filled circle or a ring.
My activity contains a grid of these circles, populated from the database, using a cursor adapter. In the bindView for the adapter, I set up properties on the custom view such as what color to make the circle and a boolean flag for whether or not to draw as a 'filled' circle or a ring.
public void bindView(View view, Context context, Cursor cursor) {
CustomCircle circle = (CustomCircle) view.findViewById(R.id.custom_circle);
// Set up the color of the Circle
int index = cursor.getColumnIndex("Color");
String colorString = "#" + cursor.getString(index);
int color = Color.parseColor(colorString);
circle.setFillColor(color);
// Set up the layout of the circle
index = cursor.getColumnIndex("count");
int totalCount = cursor.getInt(index);
if (totalCount > 0)
{
circle.setFillInCircle(true);
}
}
Inside the onSizeChanged for the custom view I have to modify the diameter to adjust for the stroke size because stroke width grows in an equal distance toward and away from the center of the circle.
On the initial OnCreateView call I set up the cursor adapter with a call to get all elements in order by color. This initially looks fine as all elements are marked to draw as rings as default. However, the problem starts occurring once I modify one of the circle elements on the top row or bottom row of the grid view (one of these rows will be out of view when the other is in view due to the size of the screen) to be 'filled'.
Now, erratically, I see behavior where some of the elements on either end will be drawn as filled circles but with the small diameter intended for the stroke style. This includes both custom views with the fill turned on and custom views next to them that are not turned on. You can scroll up and back down and they circles will have a different configuration!
Breakpoints in the onDraw call reveal scenarios where the reported radius is the smaller style but the flag for filling is turned on (when it should be off).
So I'm trying to figure out what is happening during the scroll. What I assumed was that the cursor adapter will lazily re-bind elements, thus updating all the necessary properties, and then onSizeChanged will be called, thus ensuring my logic is sound. Unfortunately, it appears onSizeChanged is firing only sometimes.
What, in terms of view binding, onSizeChanged, and onDraw, is expected to occur during scroll of a grid mapped to data with a cursor adapter?
I found the solution - it was two problems.
First, there is no guarantee of onSizeChanged executing while scrolling. I moved the logic to onMeasure and ensured I was calling requestLayout() to get the proper diameter.
Second, adapters re-use visuals. This means you have to update every property to ensure they're correct; you have no guarantee of class defaults being true. In my case I updated the above method to read as such:
public void bindView(View view, Context context, Cursor cursor) {
CustomCircle circle = (CustomCircle) view.findViewById(R.id.custom_circle);
// Set up the color of the Circle
int index = cursor.getColumnIndex("Color");
String colorString = "#" + cursor.getString(index);
int color = Color.parseColor(colorString);
circle.setFillColor(color);
// Set up the layout of the circle
index = cursor.getColumnIndex("count");
int totalCount = cursor.getInt(index);
if (totalCount > 0)
{
circle.setFillInCircle(true);
}
else
{
circle.setFillInCircle(false);
}
}
These combined solved the problem.
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 need to change the background of the child view in Expandable list view when child is clicked.
Child row layout is something like:
<RelativeLayout> //Selector is placed for this layout
....
<RelativeLayout>
....
<RelativeLayout>
....
<TextView>
....
....
selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable= "#drawable/greyish"/>
</selector>
Now, when i clicked on TextView i want to change the background of whole row ( top most Relative layout comprise on every view with in child layout). How can i trigger the selector of top level relative layout.
Also, when OnChildClick() receives callback then row's background changes( because of selector placed in top level layout).
My attempt is:
In TextView's onlclick method:
((RelativeLayout)(nameView.getParent().getParent().getParent())).setPressed(true);
but this is not resulting in row layout to change background color.
Issue:
ultimately you want to trigger the selector of parentView from its childView.
Solution
In your parent layout,add this line:
android:addStatesFromChildren="true"
and if you have the reference of parentView in your java code then you can achieve the task by using:
parentView.setAddStatesFromChildren(true);
where,parentView is your parent layout i.e.:RelativeLayout
Note:
make sure that your childview is not duplicating parent's state.
i.e.: android:duplicateParentState or childView.setDuplicateParentState(true)
I hope it will be helpful !
Could you not just give an id to the layout where you want the elements to be colored and then something like:
layout_with_child_views = (RelativeLayout)nameView.getRootView().findViewById(id)
If your method returns the correct view then you could of course also stick to that.
Then fetch all child elements and change the background color:
for (int i = 0; i < layout_with_child_views.getChildCount(); i++) {
View child = (View) layout_with_child_views
.getChildAt(i);
tintBackground(child);
}
private void tintBackground(View view) {
ColorDrawable[] color = { new ColorDrawable(Color.WHITE),
new ColorDrawable(Color.GREY) };
TransitionDrawable trans = new TransitionDrawable(color);
view.setBackgroundDrawable(trans);
trans.startTransition(500);
}
Edit: I have been searching abit and to me it seems like you should be able to use the available listeners of ExpandableListView, so that in your ExpandableListAdapter:
#Override
public void onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
// use the parent to set default color to all other entries
// v is the view within the expandable list/ListView that was clicked
for (int i = 0; i < v.getChildCount(); i++) {
View child = (View) v.getChildAt(i);
// do highlighting
}
}
I have not tried this myself and am currently unable to setup a test project. Just wanted to give you an alternative approach in case you have not tried something similar.
In Android, by default when you long click on a list item, it goes from the highlight color to white indicating that the user has held it down and a context item will be displayed. Also, you can use the trackball (or arrow buttons on some phones) to select list items rather then using your fingers.
However, I have a ListView whose item's views I am calling setBackgroundColor on, and both of those expected behaviors no longer work. Anybody know why this is and how to fix it?
Notes: Setting the background color in the xml is not an option because I need to be able to set/change the color dynamically.
The code for my newView function is as follows:
#Override
public View newView(Context ctx, Cursor cursor, ViewGroup parent)
{
View view = new View(mCtx);
final LayoutInflater li = (LayoutInflater) mCtx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = li.inflate(R.layout.task_list_item, null);
return view;
}
By default, ListView has a Selector that will play a TransitionDrawable when you longpress a list item. However, if your list item view has a solid background, then you won't be able to see the selector's longpress animation (or on any other states) , because it's covered up by the list item's background.
If you want to see the selector's longpress animation/selected/pressed state, then the list item's has to have a transparent background when the item is selected/pressed/longpressed. You can do it by using a StateListDrawable as your item's background instead of a solid color.
Here is a sample of StateListDrawable for that purpose:
public class ColorfulListItemDrawable extends StateListDrawable {
private final PaintDrawable mColor;
public ColorfulListItemDrawable(int color) {
mColor = new PaintDrawable(color);
initialize();
}
private void initialize() {
Drawable color = mColor;
Drawable selected = new ColorDrawable(Color.TRANSPARENT);
addState(new int[] {android.R.attr.state_pressed, android.R.attr.state_enabled,
android.R.attr.state_window_focused}, selected);
addState(new int[] {android.R.attr.state_pressed, android.R.attr.state_enabled,
android.R.attr.state_window_focused,android.R.attr.state_selected}, selected);
addState(new int[] {android.R.attr.state_enabled,android.R.attr.state_window_focused, android.R.attr.state_selected}, selected);
addState(new int[] {}, color);
}
public void setColor(int color) {
mColor.getPaint().setColor(color);
mColor.invalidateSelf();
}
}
When you set the background color, you're overriding the default background, which seems to be a color animation. If you want a different color, you'll have to create the animation with the color you want.
You want to create a Selector that deals with the Selected state.
As you can't use an XML solution, you want to create a StateListDrawable programmatically and set it with ListView.setSelector.
This probably is happening because you are just setting single color to the layout.. where as by default it has something like stateList and it has different colors for different state (clicked, focussed, lingClicked) etc... you can create one and use it to set the backGround...
I have a one line solution if you're using ListView (it probably works on all views), in your ListView code, add android:drawSelectorOnTop="true".
For example:
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/listID"
android:drawSelectorOnTop="true"
...
/>