I'm trying to set a custom attribute to my view programmatically, to set a validation state.
First, I created this layout for a text field:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#android:color/transparent" />
</shape>
</item>
<item android:right="1dp" android:left="1dp">
<shape>
<solid android:color="#color/state_color" />
</shape>
</item>
<!-- main color -->
<item
android:bottom="1.5dp"
android:left="2.5dp"
android:right="2.5dp">
<shape>
<solid android:color="#android:color/white" />
</shape>
</item>
<!-- draw another block to cut-off the left and right bars -->
<item android:bottom="5.0dp">
<shape>
<solid android:color="#android:color/white" />
</shape>
</item>
Then defined this attribute:
<attr name="validation_state" format="enum">
<enum name="None" value="0"/>
<enum name="Error" value="1"/>
<enum name="Warning" value="2"/>
<enum name="Success" value="3"/>
</attr>
I also defined these color definitions state_color.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:color="#color/state_error"
app:validation_state="Error"/>
<item
android:color="#color/state_warning"
app:validation_state="Warning"/>
<item
android:color="#color/state_success"
app:validation_state="Success"/>
<item
android:color="#color/state_default"/>
And last I created an own EditText class which extends the one of the Android framework
private static final int[] STATE_MANDATORY = { R.attr.mandatory };
private static final int[] STATE_READONLY = { R.attr.readonly };
private static final int[] STATE_VALIDATION_STATE = { R.attr.validation_state };
private boolean _mandatory = false;
private boolean _readonly = false;
private ValidationState _validationState = ValidationState.NONE;
public mcEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
public void setMandatory(final boolean mandatory)
{
_mandatory = mandatory;
refreshDrawableState();
}
#Override
public void setReadOnly(final boolean readonly)
{
_readonly = readonly;
refreshDrawableState();
}
#Override
public void setValidationState(final ValidationState state)
{
_validationState = state;
refreshDrawableState();
}
#Override
protected int[] onCreateDrawableState(int extraSpace)
{
final int[] drawableState = super.onCreateDrawableState(extraSpace + 3);
if (_mandatory)
{
mergeDrawableStates(drawableState, STATE_MANDATORY);
}
if (_readonly)
{
mergeDrawableStates(drawableState, STATE_READONLY);
}
if (_validationState != ValidationState.NONE)
{
mergeDrawableStates(drawableState, STATE_VALIDATION_STATE);
}
return drawableState;
}
I've added this color definition to my view and it also recognises it, so the error state gets shown. But now I don't know how to switch between the different states. I need to set programmatically the attribute "validation_state", but how is that possible?
It seems that android does not support enum attributes for this kind of work. You must have to work with boolean attributes
<attr name="validation_state_none" format="boolean"/>
<attr name="validation_state_error" format="boolean"/>
...
The most common example of what you trying to do is like focusable, editable attributes. And it's handled with atomic booleans attributes in android source
Another solution that might help you (Not tested) is to create your own drawable programmatically. Take a look at DrawableContainer and StateListDrawable
Related
I am having a problem with MaterialCalendarView library.
Everything is fine until I select a day with a decorator because the decorator has the same color of the selection color.
Here is the normal click:
and the issue:
the decorator code:
public class EventDecoratorMonth implements DayViewDecorator {
private CalendarDay date;
private Context context;
public EventDecoratorMonth(CalendarDay date, Context context) {
this.date = date;
this.context = context;
}
#Override
public boolean shouldDecorate(CalendarDay day) {
return day.equals(date);
}
#Override
public void decorate(DayViewFacade view) {
if (context != null)
view.addSpan(new ForegroundColorSpan(ContextCompat.getColor(context, R.color.orange)));
}
}
and through xml the selection color: app:mcv_selectionColor="#color/orange"
the selected day text color is white, I used mcv_dateTextAppearance with a selector to change it to white when android:state_checked="true" and grey in every other case.
The problem is when a day with a decorator is selected that the mcv_dateTextAppearance is not applied.
Edit:
my selector
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/white" android:state_checked="true" />
<item android:color="#color/white" android:state_pressed="true" />
<item android:color="#color/textGrey" android:state_enabled="false" />
<item android:color="#color/textGrey" android:state_checked="false" />
<item android:color="#color/textGrey" />
</selector>
How to fix this?
EDIT 2:
I fixed using a decorator with ForegroundColorSpan color set to white, and on changeSelected date I remove old one and set new one
Try using this selector for your text color
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/white" android:state_checked="true" />
<item android:color="#color/white" android:state_pressed="true" />
<item android:color="#color/grey" android:state_enabled="false" />
<item android:color="#color/grey" />
</selector>
In my app I have created one Listview. When I click on the row, I want to change the Listview row color as Lightgray color and textcolor as a Blue color.
For this I have tried the code below but only row background color is changing not the textcolor.
mainListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
for (int j = 0; j < parent.getChildCount(); j++) {
parent.getChildAt(j).setBackgroundColor(Color.TRANSPARENT);
view.setBackgroundColor(Color.LTGRAY);
rowText = (TextView) findViewById(R.id.rowitem);
rowText.setTextColor(Color.BLUE);
}
}
});
}
first enable the android:ListSelector attribute in your ListView
ListView android:id="#+id/android:list" android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/Tablayoutdesign"
android:cacheColorHint="#000000"
android:dividerHeight="1dip"
android:layout_marginTop="63dip"
android:layout_marginBottom="40dip"
/>
Thank create a selector (listselector.xml)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Selected -->
<item
android:state_focused="true"
android:state_selected="false"
android:drawable="#drawable/focused"/>
<!-- Pressed -->
<item
android:state_selected="true"
android:state_focused="false"
android:drawable="#drawable/selected" />
</selector>
Than go for colors.xml
<resources>
<drawable name="focused">#ff5500</drawable>
<drawable name="selected">#FF00FF</drawable>
</resources>
and with some Java magic:
listview.setSelector(R.drawable.listselector)
Thanks to #sankar-anesh
List State Pressed
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#4285f4" />
<corners android:radius="2dp" />
</shape>
</item>
<item
android:bottom="2dp"
android:left="0dp"
android:right="0dp"
android:top="0dp">
<shape android:shape="rectangle">
<solid android:color="#4285f4" />
<corners android:radius="2dp" />
</shape>
</item>
</layer-list>
List view background when not pressed
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#FFF" />
<corners android:radius="2dp" />
</shape>
</item>
<item
android:bottom="2dp"
android:left="0dp"
android:right="0dp"
android:top="0dp">
<shape android:shape="rectangle">
<solid android:color="#FFF" />
<corners android:radius="2dp" />
</shape>
</item>
</layer-list>
List view Selector
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/card_state_pressed" android:state_pressed="true" />
<item android:drawable="#drawable/card_background" />
</selector>
First create a selector drawable like this :
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#android:color/red"
android:state_pressed="true" />
<item android:drawable="#android:color/white" />
</selector>
Then
StateListDrawable selector = new StateListDrawable();
selector.addState(new int[] { android.R.attr.state_pressed }, getResources().getDrawable(R.color.red));
selector.addState(new int[] {}, getResources().getDrawable(R.color.white));
view.setBackgroundDrawable(selector);
Change the
rowText = (TextView) findViewById(R.id.rowitem);
to
rowText = (TextView)view.findViewById(R.id.rowitem);
since you should find the textview in the inflated view, not independently.
in my app there are three buttons yes no maybe. here I changed the colour of the button when user click any button that colour changed. when user clicks the button it stored as 1 0 2 in table based on user select the button. but when I go some other option in app and return back to this the buttons are as it normal. here that should be highlighted which is selected by user.
the following code for yes no maybe button
yesBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// highlight the button when clicked
yesBtn.setBackgroundColor(Color.YELLOW);
noBtn.setBackgroundColor(Color.BLUE);
maybeBtn.setBackgroundColor(Color.BLUE);
responseLayout.setVisibility(View.GONE);
//If user clicks yes button in invitation response layout,response would be stored as 1 for event user
final int response = 1;
final long eventId = eventMOs.get(position).getEventId();
userMO.setIsAttending(response);
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... arg0) {
return userDelegate.updateEventUserRelationShipMapping(userMO, eventId);
}
}.execute(null, null, null);
}
});
noBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
yesBtn.setBackgroundColor(Color.BLUE);
noBtn.setBackgroundColor(Color.YELLOW);
maybeBtn.setBackgroundColor(Color.BLUE);
responseLayout.setVisibility(View.GONE);
//If user clicks no button in invitation response layout,response would be stored as 0 for event user
final int response = 0;
final long eventId = eventMOs.get(position).getEventId();
userMO.setIsAttending(response);
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... arg0) {
return userDelegate.updateEventUserRelationShipMapping(userMO, eventId);
}
}.execute(null, null, null);
}
});
maybeBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
yesBtn.setBackgroundColor(Color.BLUE);
noBtn.setBackgroundColor(Color.BLUE);
maybeBtn.setBackgroundColor(Color.YELLOW);
responseLayout.setVisibility(View.GONE);
//If user clicks maybe button in invitation response layout,response would be stored as for event user
final int response = 2;
userMO.setIsAttending(response);
final long eventId = eventMOs.get(position).getEventId();
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... arg0) {
return userDelegate.updateEventUserRelationShipMapping(userMO, eventId);
}
}.execute(null, null, null);
}
});
this yes no maybe layout shows when event is clicked
here events are list view when I clicked single event it should show for each event what I have clicked
use selectors for states like this hope this will help you...
create btn_stae.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="#android:integer/config_shortAnimTime">
<item android:drawable="#drawable/hidden_bg" android:state_focused="true" android:state_pressed="false"/>
<item android:drawable="#drawable/bg_round" android:state_pressed="true"/>
<item android:drawable="#drawable/border" android:state_enabled="false"/>
<item android:drawable="#drawable/active" />
</selector>
active.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="4dp" />
<stroke
android:width="2dp"
android:color="#color/green_dark" />
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp" />
<solid android:color="#color/white" />
</shape>
border.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="4dp" />
<stroke
android:width="2dp"
android:color="#color/button_bg_stroke"/>
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp" />
<solid android:color="#color/button_bg" />
</shape>
bg_round.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/switch_thumb_normal_material_dark" />
<stroke
android:width="2dp"
android:color="#color/background_material_light" />
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp" />
<corners android:radius="4dp" />
</shape>
hidden_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#color/bg" />
<stroke
android:width="2dp"
android:color="#color/light" />
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp" />
<corners android:radius="4dp" />
</shape>
If the requirement is only for save the 3 buttons state you can use sharedpreference to save the selected button value.
If yes is selected save value as 0, No is selected save as 1, May be clicked save 2.
Code to save value in sharedpreference. Write the similar code on your button click listeners.
SharedPreferences sharedpreferences = getSharedPreferences("PREFERENCE", Context.MODE_PRIVATE);
int clickedButton = sharedpreferences.getInt("clicked_btn", 1); //1 is the default value.
SharedPreferences sharedpreferences = getSharedPreferences("PREFERENCE", Context.MODE_PRIVATE);
Editor editor = sharedpreferences.edit();
editor.putInt("clicked_btn", 0); //value will be 0 or 1 or 2
editor.commit();
And get the saved value on next time in activity onResume() method like this
SharedPreferences sharedpreferences = getSharedPreferences("PREFERENCE", Context.MODE_PRIVATE);
int clickedButton = sharedpreferences.getInt("clicked_btn", 1); //1 is the default value.
Add switch case and change button color of last saved button based on the clickedButton value.
Switch case should be like this
switch (clickedButton)
{
case 0: //here change yes button color
break;
case 1: //here change no button color
break;
case 2: //here change may be button color
break;
default: //here default button color for saved button id
break;
}
Hope this will help for you.
I'm trying to draw drawable consisting of circle and rectangle. It's working fine while api is set to 23. I noticed that following attributes of 'item' have been added in newest api: height, gravity, weight. Is it possible to get the effect in older sdk?
Drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:height="5dp"
android:gravity="center_vertical"
android:left="5dp">
<shape android:shape="rectangle">
<size
android:width="50dp"
android:height="5dp" />
<solid android:color="#125572" />
</shape>
</item>
<item
android:width="20dp"
android:height="20dp"
android:gravity="center_vertical">
<shape android:shape="oval">
<solid android:color="#125572" />
<size
android:width="20dp"
android:height="20dp" />
</shape>
</item>
</layer-list>
Image using api 23:
Image using api 22:
I know this question is quite old but I solved this problem and maybe it is useful for someone even now.
For the solution I created two classes.
One class called MyLayerDrawable that extends LayerDrawable. The important thing to keep in mind about this class is that you can get the top and the left insets for each layer.
public class MyLayerDrawable extends LayerDrawable{
private List<Layer> layers;
//some code here
public static class Layer{
private Drawable drawable;
private int topInset;
private int leftInset;
public Layer(Drawable drawable,int topInset,int leftInset){
this.leftInset=leftInset;
this.drawable=drawable;
this.topInset=topInset;
}
public Drawable getDrawable(){
return drawable;
}
public int getTopInset(){
return topInset;
}
public int getLeftInset(){return leftInset;}
}
The second class I created is called MyImageViewPatch that owns an ImageView.
The only public method of this class is setImageMyLayerDrawable(MyLayerDrawable layerDrawable). This method delegates setting the image drawable to the ImageView that it owns:
public void setImageMyLayerDrawable(MyLayerDrawable layerDrawable){
imageView.setImageDrawable(layerDrawable);
}
But before calling the setImageDrawable method an observer object has been added to the ImageView in the MyImageViewPatch constructor. This observer is called before drawing the Drawable in the ImageView:
imageView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
MyLayerDrawable layerDrawable=(MyLayerDrawable)imageView.getDrawable();
int numberOfLayers=layerDrawable.getNumberOfLayers();
Drawable drawable;
Rect bounds;
for(int i=0;i<numberOfLayers;i++){//for each layer
drawable=layerDrawable.getDrawable(i);
bounds=drawable.getBounds();
bounds.top=layerDrawable.getLayer(i).getTopInset();
bounds.left=layerDrawable.getLayer(i).getLeftInset();
if(drawable.getIntrinsicHeight()<bounds.height()){
bounds.bottom=drawable.getIntrinsicHeight()+layerDrawable.getLayer(i).getTopInset();
}
if(drawable.getIntrinsicWidth()<bounds.width()){
bounds.right=drawable.getIntrinsicWidth()+layerDrawable.getLayer(i).getLeftInset();
}
}
return true;
}
});
As you can see before drawing the MyLayerDrawable the bounds for each Layer are adjusted based on the left and top insets; this is the key part to get the drawables drawn in the correct size instead of stretched.
Here is the shapes xml file:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:height="5dp"
android:gravity="center_vertical"
android:left="5dp"
android:top="8dp">
<shape android:shape="rectangle">
<size
android:width="50dp"
android:height="5dp" />
<solid android:color="#125572" />
</shape>
</item>
<item
android:width="20dp"
android:height="20dp">
<shape android:shape="oval">
<solid android:color="#125572" />
<size
android:width="20dp"
android:height="20dp" />
</shape>
</item>
</layer-list>
To centre the rectangle vertically I used android:top="8dp" instead of android:gravity="center_vertical".
Here is the code for the Main Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView iv=(ImageView)findViewById(R.id.imageView);
MyLayerDrawable myLayerDrawable=MyLayerDrawable.Builder.build(getApplicationContext(),R.drawable.layer_d_example);
MyImageViewPatch myImageViewPatch=new MyImageViewPatch(iv);
myImageViewPatch.setImageMyLayerDrawable(myLayerDrawable);
}
}
I have the complete code in github. You may check it out: https://github.com/marcosbses/my_layout_drawable.git
I want to change color of underline in Edittext and i follow some tutorials to do this.
I create this xml file:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle" >
<solid android:color="#00FFFFFF" />
<padding android:bottom="2dp" />
<stroke
android:width="1dp"
android:color="#FFFFFF" />
</shape>
</item>
</layer-list>
But i only do the underline not all rectangle, similiar as default line but white inside of blue and solid background transpartet.
How can i do this?
Thanks
You can change it programatically too:
public static void changeEditTextUnderlineColor(EditText editText) {
int color = Color.parse("#[putColorHere]")
Drawable drawable = editText.getBackground();
drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
editText.setBackground(drawable);
} else {
editText.setCompoundDrawables(null, null, drawable, null);
}
}
you can change Edit color Underline in EditText specifying it in styles.xml. In your app theme styles.xml add the following.
<item name="android:textColorSecondary">#color/primary_text_color</item>