Hi I have to make layout as below, edit text has to be in TextInputLayout to have error and floating hint functionality, and spinner on the right must have underline. My question is how to do it, because when I'm adding EditText into TextInputLayout there is a padding bellow and both underlines aren't in the same line. Is it possible to measure somehow this error container height?
So there are two possibility to do this:
Set errorEnabled as false and create custom TextView with error text.
Add extra invisible TextView to the bottom of second view with style and font size which can be found in TextInputLayout constructor. I'm not using this method but in my case it is 12sp.
This is a common problem and one that I had to deal with myself just the other day. You can always take a look at the measurements on the guidelines here rather than needing to look into the code.
With regards to making a spinner match you can start with adding a background like this drawable
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:top="-1dp"
android:left="-1dp"
android:right="-1dp"
android:bottom="1dp" >
<shape android:shape="rectangle">
<padding android:top="4dp" android:bottom="4dp" />
<stroke android:width="1dp" android:color="#color/my_grey"/>
</shape>
</item>
</layer-list>
You'll probably want to add android:padding="0dp" to the Spinner and rather than using one of th simple_... layouts which add padding which does not match EditText, return a plain TextView as your view returned from the adapter but continue to use the simple_... layout for the dropdown view, like the adapter example below
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
//convertView = mInflater.inflate(R.layout.support_simple_spinner_dropdown_item, parent, false);
convertView = new TextView(parent.getContext());
}
//if you want to mimick the floating hint behaviour from the edit text,
//you can animate the label visibility here
return populateView(position, convertView, parent);
}
private View populateView(int position, View convertView, ViewGroup parent) {
// in here set your values as you usually would
return convertView;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.support_simple_spinner_dropdown_item, parent, false);
}
return populateView(position, convertView, parent);
}
Now provided your margins on the EditText and Spinner match, they will line up. Although in some layouts I have to set android:layout_marginTop="0dp" on the Spinner
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 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.
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
How to change the margin between two groups in an ExpandableListView?
If I insert two groups into an ExpandableListView, I got the following
PARENT1 (collapsed)
PARENT2 (collapsed)
How can I make it look like this?
PARENT1 (collapsed)
(some space)
PARENT2 (collapsed)
Note, I want to the space between collapsed group only. No space among child items
Add padding
#Override
public View getGroupView(final int groupPosition, final boolean isExpanded, View convertView, final ViewGroup parent) {
...
convertView.setPadding(0, 30, 0, 0);
return convertView;
}