I've recently updated my phone to Android Marshmallow and ran my existing app on it, but noticed a difference in color behavior: When applying changes to the background of a view (drawable), all views that share the same background (reference) will also the same changes applied. While previously, this was not the case.
Example
In this example, I have a two views with the same background color, and I want to change the alpha level of one of both views.
First we define the views in the layout:
<LinearLayout
android:id="#+id/test1"
android:orientation="horizontal"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#color/testColor2">
</LinearLayout>
<LinearLayout
android:id="#+id/test2"
android:orientation="horizontal"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#color/testColor1"
android:layout_marginLeft="5dp">
</LinearLayout>
Both views share the same background color or drawable:
<color name="testColor1">#3F51B5</color>
<color name="testColor2">#3F51B5</color>
The result looks like this:
Now we are going to change one of the two background, like this:
LinearLayout test1 = (LinearLayout) findViewById(R.id.test1);
LinearLayout test2 = (LinearLayout) findViewById(R.id.test2);
test1.getBackground().setAlpha(80);
Which results in this:
However, the desired and expected result is obviously this:
Download the sample project here.
A few thoughs:
When setting the Alpha level trough XML, this behavior does not apply.
It does not matter if both views refer to a different color definition in colors.xml (like in the example), refer to the same color definition of both have the same color (hex) directly in the view's xml file.
Question
How can I make changes to a view's background without this affecting other views that share the same background. Preferably while still being able to use a background that directly refers to a color defined in the color's xml file
Most likely the class of each view's background and constantstate are
the same object. It seems as if the two color resources have been
"merged" somewhere -- meaning they have shared ConstantState. Maybe in
the Resources class' caching? I would've expected them to stay
separate since they're different resources (albeit with the same color
value), but apparently not.
– Snild Dolkow
The ColorDrawable's state stores alpha, so any changes to one will change the others. To prevent this, you can first call mutate() on the drawable, separating the two drawables (by making a copy of the state).
In the example, this would result in using test1.getBackground().mutate().setAlpha(80); instead of directly applying the alpha.
Related
I've recently updated my phone to Android Marshmallow and ran my existing app on it, but noticed a difference in color behavior: When applying changes to the background of a view (drawable), all views that share the same background (reference) will also the same changes applied. While previously, this was not the case.
Example
In this example, I have a two views with the same background color, and I want to change the alpha level of one of both views.
First we define the views in the layout:
<LinearLayout
android:id="#+id/test1"
android:orientation="horizontal"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#color/testColor2">
</LinearLayout>
<LinearLayout
android:id="#+id/test2"
android:orientation="horizontal"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#color/testColor1"
android:layout_marginLeft="5dp">
</LinearLayout>
Both views share the same background color or drawable:
<color name="testColor1">#3F51B5</color>
<color name="testColor2">#3F51B5</color>
The result looks like this:
Now we are going to change one of the two background, like this:
LinearLayout test1 = (LinearLayout) findViewById(R.id.test1);
LinearLayout test2 = (LinearLayout) findViewById(R.id.test2);
test1.getBackground().setAlpha(80);
Which results in this:
However, the desired and expected result is obviously this:
Download the sample project here.
A few thoughs:
When setting the Alpha level trough XML, this behavior does not apply.
It does not matter if both views refer to a different color definition in colors.xml (like in the example), refer to the same color definition of both have the same color (hex) directly in the view's xml file.
Question
How can I make changes to a view's background without this affecting other views that share the same background. Preferably while still being able to use a background that directly refers to a color defined in the color's xml file
Most likely the class of each view's background and constantstate are
the same object. It seems as if the two color resources have been
"merged" somewhere -- meaning they have shared ConstantState. Maybe in
the Resources class' caching? I would've expected them to stay
separate since they're different resources (albeit with the same color
value), but apparently not.
– Snild Dolkow
The ColorDrawable's state stores alpha, so any changes to one will change the others. To prevent this, you can first call mutate() on the drawable, separating the two drawables (by making a copy of the state).
In the example, this would result in using test1.getBackground().mutate().setAlpha(80); instead of directly applying the alpha.
just a question wondering when I was working on my app
let say I have image which I want to make it semi-transparent but I don't want to add about image into the app (as in create another one and add it in)
is there a way to do it??
You have to set the alpha value of the image. ( If i understood you correctly)
If you load this Image in to a ImageView, you can set it from xml like this:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/your_image_in_res"
android:alpha="1"/>
where according to the developers site "alpha property of the view, as a value between 0 (completely transparent) and 1 (completely opaque). " Play with the value to get the desired effect.
If you have your image int the res/drawable folder, you can use it anywhere in your code. In xml almost all elements have the following parameter:
android:background="#drawable/im_your_image"
. You just have to set this in all places, where you want this to be your background, for the parent views background. (e.g. your MainActivitys RelativeLayout that you inflate in the onCreate funciton. You see the image is put only once in the package, but this way you can set it several times as a background.
I want to customize Buttons for my application. The application has a color picker where the user will select color and I have to set that particular start/end color to the buttons. These colro values will be stored in an object "Utility".
Basically from start only, I want to use "Utility" object to set colors for background, text color, font, etc. And again when the color is changed by the user I got to change it to the buttons and refresh them. And also to save colors in a file, so next time user starts app, it comes up with the last color selected.
I couldn't find <selector> to be the best option, as I wont be able to change the color in xml. What can be the best option for such requirement ?
UPDATIONS :
#jitendra, from your answer I got somethign helpful. I use GradientDrawable to set colors of my buttons. In my onCreate() of the Activity, I call a method RefreshComponents() that sets the background of root, text color/size of buttons and gradient colors of the buttons. It works properly, but the only problem I see is the on applying GradientDrawable to the button the gap between 2 buttons is lost.
This is the image WITHOUT applying GradientDrawable :
On applying GradientDrawable the output is :
You see the size of button is increased a bit from all the sides. If I apply to next button also, they both touch eachother. My xml for the above is :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainroot" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical"
android:paddingTop="35dip" android:paddingBottom="35dip"
android:paddingLeft="35dip" android:paddingRight="35dip"android:gravity="center" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainrow1" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:orientation="horizontal"
android:layout_marginBottom="15dip" android:gravity="center_horizontal" >
<Button android:text="Accounting" android:id="#+id/accBtn" android:layout_width="80dip" style="#style/TileButtonStyle" />
<Button android:text="Data" android:id="#+id/dataBtn" android:layout_width="80dip" android:layout_height="fill_parent"></Button>
<Button android:text="Information" android:id="#+id/infoBtn" android:layout_width="80dip" android:layout_height="fill_parent" android:ellipsize="end"></Button>
</LinearLayout>
..... Other lineasr layout with same parameters as above child
And the GradientDrawable that I create is :
public static GradientDrawable getButtonDrawable(Button btn) {
int colors[] = {getStartColor(), getEndColor()};
GradientDrawable grad = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
grad.setCornerRadius(5f);
return grad;
}
And finally in my onCreate(), I add :
GradientDrawable btnGradient = Utility.getButtonDrawable(btn1);
btn1.setBackgroundDrawable(btnGradient);
What is going wrong here ? Is the margin around the button becoming 0 ? Do I have to set bounds for the grad, or again set LayoutParams for the button ?
Any help is appreciative to help me achieve my goal.
Thanks
You can Create StateListDrawable Object dynamically in java file and set as background and sources of applcation components.
Android has Themes and Styles, but they are a development-time feature and can't be manipulated at runtime. However, different predefined themes can be applied at runtime.
So you can have a set of predefined themes, with fixed view properties (colors, fonts, etc..) and give user an option to choose a theme at runtime.
But, if you need to change every particular view property, then you will need to roll your own "theme" system. Which means you will need to have properties stored somewhere and applied each time a view is built.
Tvd! I incline to agree with Peter Knego and Jitender Sharma. Furthermore, I think/believe you can setOnClickListener on those buttons of yours and perform your color changing stuff with the code that rests inside the setOnClickListenermethod assigned to every button. In addition to this, you'll have to configure your color.xml file and custom themes. There's a lot of work to be done. I'm not really sure which is the best way though. I strongly suggest you to go through the android learning stuff I'd provided to you in my previous answer. Only they can give you a detailed insight and a solid idea to go ahead. All the best!
Oh I got the solution :
I added layout_marginRight attribute to buttons and that did the work.
Though I am still concerned, without GradientDrawable the buttons had margin betweenthem then after applying GradientDrawable why is the default margin lost ? Why is the need of additional layout_marginRight to be added ?
If anyone yet has answer for this, please let me know.
Thanks
I am trying to, somewhat clone the design of an activity from a set of slides on Android UI design. However I am having a problem with a very simple task.
I have created the layout as shown in the image, and the header is a TextView in a RelativeLayout. Now I wish to change the background colour of the RelativeLayout, however I cannot seem to figure out how.
I know I can set the android:background property in the RelativeLayout tag in the XML file, but what do I set it to? I want to define a new colour that I can use in multiple places. Is it a drawable or a string?
Additionally I would expect there to be a very simple way to this from within the Eclipse Android UI designer that I must be missing?
I am a bit frustrated currently, as this should be an activity that is performed with a few clicks at maximum. So any help is very appreciated. :)
You can use simple color resources, specified usually inside res/values/colors.xml.
<color name="red">#ffff0000</color>
and use this via android:background="#color/red". This color can be used anywhere else too, e.g. as a text color. Reference it in XML the same way, or get it in code via getResources().getColor(R.color.red).
You can also use any drawable resource as a background, use android:background="#drawable/mydrawable" for this (that means 9patch drawables, normal bitmaps, shape drawables, ..).
The above answers are nice.You can also go like this programmatically if you want
First, your layout should have an ID. Add it by writing following +id line in res/layout/*.xml
<RelativeLayout ...
...
android:id="#+id/your_layout_id"
...
</RelativeLayout>
Then, in your Java code, make following changes.
RelativeLayout rl = (RelativeLayout)findViewById(R.id.your_layout_id);
rl.setBackgroundColor(Color.RED);
apart from this, if you have the color defined in colors.xml, then also you can do programmatically :
rl.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.red));
You can use android:background="#DC143C", or any other RGB values for your color. I have no problem using it this way, as stated here
The
res/values/colors.xml.
<color name="red">#ffff0000</color>
android:background="#color/red"
example didn't work for me, but the
android:background="#(hexidecimal here without these parenthesis)"
worked for me in the relative layout element as an attribute.
If you want to change a color quickly (and you don't have Hex numbers memorized) android has a few preset colors you can access like this:
android:background="#android:color/black"
There are 15 colors you can choose from which is nice for testing things out quickly, and you don't need to set up additional files.
Setting up a values/colors.xml file and using straight Hex like explained above will still work.
4 possible ways, use one you need.
1. Kotlin
val ll = findViewById<LinearLayout>(R.id.your_layout_id)
ll.setBackgroundColor(ContextCompat.getColor(this, R.color.white))
2. Data Binding
<LinearLayout
android:background="#{#color/white}"
OR more useful statement-
<LinearLayout
android:background="#{model.colorResId}"
3. XML
<LinearLayout
android:background="#FFFFFF"
<LinearLayout
android:background="#color/white"
4. Java
LinearLayout ll = (LinearLayout) findViewById(R.id.your_layout_id);
ll.setBackgroundColor(ContextCompat.getColor(this, R.color.white));
Android studio 2.1.2 (or possibly earlier) will let you pick from a color wheel:
I got this by adding the following to my layout:
android:background="#FFFFFF"
Then I clicked on the FFFFFF color and clicked on the lightbulb that appeared.
Kotlin
linearLayout.setBackgroundColor(Color.rgb(0xf4,0x43,0x36))
or
<color name="newColor">#f44336</color>
-
linearLayout.setBackgroundColor(ContextCompat.getColor(vista.context, R.color.newColor))
The answers above all are static. I thought I would provide a dynamic answer. The two files that will need to be in sync are the relative foo.xml with the layout and activity_bar.java which corresponds to the Java class corresponding to this R.layout.foo.
In foo.xml set an id for the entire layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="#+id/foo" .../>
And in activity_bar.java set the color in the onCreate():
public class activity_bar extends AppCompatActivty {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.foo);
//Set an id to the layout
RelativeLayout currentLayout =
(RelativeLayout) findViewById(R.id.foo);
currentLayout.setBackgroundColor(Color.RED);
...
}
...
}
I hope this helps.
I have looked and tried a lot of different things but no matter what I end up doing the screen is always blank and I'm sure it's something really dumb I'm doing and I'm hoping someone will catch it.
I'm trying to alternate background colors but before I even get to that I need to get it so that even one background color will display properly.
First, my xml layout works fine and when I got to the layout view it displays the color just as I want it to. When I go to setContentView() in the activity that calls the xml it is never displayed and I only get a blank screen.
Second, since this initial issue described above I have tried several fixes and have numbered them accordingly. As I did a fix I usually only bothered to comment it out instead of deleting it after it didn't work. After certain lines there is a number, so if three lines have 1's behind them then those were the three lines used in attempt #1.
Third, while trying these fixes I added a colors xml file while I'll display as well.
Finally, I'll show my main activity first, xml file second, and colors file last. As you can see my ultimate goal would be to change the background dynamically but I can't even to get it to work normally right now. And FYI my splash screen works fine. But that's an image.
Thanks for you help.
public class Blink extends Activity {
long startTime= System.currentTimeMillis();
long now=0;//the current time in millis
public void OnCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//TextView backgroundColor=new TextView(this);2,3,4,5,6
//backgroundColor.setBackgroundColor(0xFFFF0000);5
//backgroundColor.setBackgroundResource(R.color.royalBlue);2,3,4
//backgroundColor.setVisibility(0);//make visible 3
setContentView(R.layout.blank);1
//setContentView(backgroundColor);4,5,6
//backgroundColor.setBackgroundColor(Color.argb(255, 255, 255, 255));6
//setContentView(R.layout.blink_blue);
//blink from royal blue to blank
/*while(true){
startTime= System.currentTimeMillis();
do{
now=System.currentTimeMillis();
setContentView(R.layout.blink_blue);
}while((-(startTime-now))>1000);
do{
now=System.currentTimeMillis();
setContentView(R.layout.blank);
}while((-(startTime-now))>1000);
}*/
}
This begins the xml file
//it is formatted properly but for some reason stack overflow doesn't like it so I'm only posting relevant lines.
//This is a Linear layout
android:id="#+id/blinkBlue"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/royalBlue"
This begins the colors file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="royalBlue">#4169e1</color>//Yes I have tried #FF4169e1 instead
<color name="plainBlue">#ff000000</color>
<color name="darkBlue">#ff000000</color>
<color name="black">#00000000</color>
<!-- I also know that the blues here aren't those colors... I'll change that when I fix this thing. -->
</resources>
You don't set colors that way, You specify colors of your Layouts that are defined in your XMLs and then you setContentView() to that XML file.
For example, lets pretend that your XML file has the name as my_layout.xml, then you have specified the color in my_color.xml so you go this way:
You write a layout in my_layout.xml
Now you write a resource XML for color as you have written above, and save it in the /res/values/my_color.xml
Set the layout (defined in my_layout.xml) background to be `android:background="#color/my_color"
in your code, use setContentView(R.layout.my_layout)
This will make my_layout.xml to be your content's layout and further the background color thing will be handled by the layout inside my_layout.xml file.
I hope that helps.
Take a look at using a state list drawable as a background. Each item can point to a shape drawable that specifies a different background color. Alternatively, use a shape drawable as a background that points to a color state list as the solid color.
If the built-in attributes available for defining a state list drawable or a color state list are not right for your application, you can use the technique shown in this thread to define your own.