Set a gradient background - android

In my Activity I need to change an ImageView background using a gradient, so I use an image with a transparent area, changing its background when I need. Here's some code:
private static View myImage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myActivityLayout);
myImage = findViewById(R.id.myImageID);
}
[...]
private void myImageUpdate() {
GradientDrawable gradient;
int[] colors = {0xFF00FF00, 0xFF0000FF};
// I make some changes to these colors..
gradient = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, colors);
myImage.setBackgroundDrawable(gradient);
}
Now, the problem is:
If I call myImageUpdate() within onCreate() method, everything works fine.
If I call myImageUpdate() from another part of the code (like an onClick callback), I can't set my backgroud!
* UPDATE *
Guys, this code is fine... I was calling my method in a wrong (not directly reachable) line! My apologies...

I don't think this will fix it since you said myImageUpdate gets called within onClick... but try this..
runOnUiThread(new Runnable() {
public void run() {
myImage.setBackgroundDrawable(gradient);
}
});
you might have to make gradient variable final..
final GradientDrawable gradient = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, colors);

Try myImage.invalidate(). This will force the system to redraw the view.

Related

RecyclerView uses wrong values

So, I use a RecyclerView for displaying a grid. In the onBindViewHolder method of its adapter I update the view content. I put a part of the update into another thread to keep the UI alive.
#Override
public void onBindViewHolder (final MovieHolder holder, final int position) {
// Blah, blah. Set movie details. Everything is fine.
// Generate a palette or load from the memory and adjust the background color of the view.
new Thread(new Runnable() {
#Override
public void run () {
Palette palette = getPalette();
final Palette.Swatch bestSwatch = findBestSwatch(palette)
if (bestSwatch != null) {
activity.runOnUiThread(new Runnable(
#Override
public void run() {
holder.layout.setBackgroundColor(bestSwatch.getRgb());
}
));
}
}
}).start();
}
It works well, except when no bestSwatch was found. Then for the first time, it displays a correct background color and when I scroll down and back it will have a random color from one of the views.
Why does RecyclerView changes the color of my view when I don't update it?
RecyclerView reuses its rows, the ViewHolders, hence its name. So your problem is that a recycled view has the background color it was set to at another recent position.
Solution to this is simple...
Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
#Override
public void onGenerated(Palette palette) {
Palette.Swatch swatch = palette.getDarkVibrantSwatch();
if (swatch == null)
swatch = new Palette.Swatch(ContextCompat.getColor(context, R.color.fallback_background), 4);
holder.layout.setBackgroundColor(swatch.getRgb());
}
});
So, you always set a BackgroundColor. When there's no swatch generated, you create one using a fallback layout background color you define at colors.xml

Android Shape Drawable changing attributes

I have several shape drawable resourses that I want use as backround for buttons and they are similar except gradient start and end color and stroke color.
The problem is that I don't want to create several similar XML files for this drawables.
I throught that I can inherit shape drawable like a styles using tag, but this is impossible.
I found this Defining XML Parent Style of Gradient / Shape / Corners but I don't understand how it's working. How he changing attributes values?
There Using parents for drawable resources I found that I can change appearance of background by layer-list that will draw layers of drawables one on top of another. But how manipulate with gradient and stroke color using layer-list?
I found that I can change appearance of buttons background in runtime, but probably there is a simpler way to do this?
the initial suggestion I made is not feasible. I thought the <shape> will return a ShapeDrawable but I was wrong, here is how I would modify the gradient.
Before the button is clicked
After the button is clicked, its background changes.
This is the Main Activity
public class MainActivity extends Activity {
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
try
{
// you can use the GradientDrawable directly, check the docs for details,
// I extended GradientDrawable just to make myself look like a badass :)
MyReflection.invokeMethod(button, new Gradient(), "setBackground");
}
catch (NoSuchMethodException e)
{
e.printStackTrace();
}
catch (InvocationTargetException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
});
}
}
Utility method to get a new method with the an object to invoke the method on, the Drawable to use as the new background, and the name of the method without the () such as setBackground to run on older versions. Reflection is SLOW. Use it sparingly.
/*
* We want to use reflection because the View.setBackground() method
* is only available on API level 16 and up.
* If you don't understand this, you can follow the tutorial provided by
* Oracle, just search for it on Google with the keyword "reflection tutorial"
*/
public class MyReflection {
public static void invokeMethod(Object receiverObject, Drawable background, String methodName)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
Class<?> clazz = View.class;
Method method = clazz.getMethod(methodName, Drawable.class);
// Allowing non-public access call to this method.
method.setAccessible(true);
method.invoke(receiverObject, background);
}
}
My custom gradient
/**
* I am extending the GradientDrawable just for fun, and also
* because I want to set the shader property for this drawable,
* you could, however, use the GradientDrawable directly.
*/
public class Gradient extends GradientDrawable {
private Paint paint;
private LinearGradient gradient;
public Gradient()
{
super();
// check the docs for LinearGradient for these parameters
gradient = new LinearGradient(0,0, 100, 100, Color.BLUE, Color.GREEN, Shader.TileMode.REPEAT);
paint = new Paint();
paint.setShader(gradient);
}
public Gradient(GradientDrawable.Orientation orientation, int[] colors)
{
super(orientation, colors);
gradient = new LinearGradient(0,0, 100, 100, Color.BLUE, Color.GREEN, Shader.TileMode.REPEAT);
paint = new Paint();
paint.setShader(gradient);
}
#Override
public void draw(Canvas canvas)
{
canvas.drawPaint(paint);
}
}
The initial background for the button
<?xml version="1.0" encoding="utf-8"?>
<!-- The initial shape with just a solid yellow color -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#ff0"/>
</shape>
hah, instead of using Reflections I used this code, based on current version, to set appropriative background
int sdk = android.os.Built.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
setBackgroundDrawable();
} else {
setBackground();
}

My drawable is not drawn after orientation change (using loadermanager)

I'm using the loadermanager for my app. On Orientation change my app can reload the TextView, but the imagestream for my drawable is not loaded the second time. On the first load the picture shows ,but after an orientation change it stays in its unchanged state. (in my case , a white square)
#Override
public void onLoadFinished(Loader<Person> loader, Person p) {
tvProfileName.setText(p.getName());
Log.i("img stream", ""+p.getImageStream());
Bitmap b = BitmapFactory.decodeStream(p.getImageStream());
Drawable d = new BitmapDrawable(getResources(), b);
ivMenuPhoto.setImageDrawable(d);
}
The setText is working and my name is loaded, even after the orientation change. But the setimagedrawable is not working. The p.getImageStream is not null...
Is my drawable maybe set before the layout is finished changing? I'm just very confused, because my TextView is working.
edited for my solution:
I added a Drawable attribute in the Person Object. So the loader can also hold that part. Then I created the getters and setters. And then I added the onResume to also set my drawable after the orientation change
#Override
public void onLoadFinished(Loader<Person> loader, Person p) {
tvProfileName.setText(p.getName());
Drawable d = new BitmapDrawable(getResources(), p.getPersonphoto());
this.personPhoto = d;
ivMenuPhoto.setImageDrawable(d);
}
#Override
protected void onResume() {
super.onResume();
ivMenuPhoto.setImageDrawable(this.personPhoto);
}

Remove image after loading screen with animation, Android

I'm trying to show a splash screen between activities. For this I'm using a handler that loads an ImageView then sets the visibility to GONE after a certain amount of time.
I wanted to make it a bit more fancy and animate it with a loadAnimation. The problem I'm running into is once the handler ends the animation stops but does not remove the loading image from the screen. Instead it is just placed as a background for the whole activity.
I would like to know how to remove the splash image after the handler stops.
Below is my code:
private static final long SPLASHTIME = 3000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main)
ImageView splash = (ImageView)findViewById(R.id.splashscreen);
final Animation a = AnimationUtils.loadAnimation(getBaseContext(),R.anim.progress_anim);
a.setDuration(1000);
splash.startAnimation(a);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
a.cancel();
splash.setVisibility(View.GONE);
}
}, SPLASHTIME);
}
XML for splash image:
<ImageView
android:id="#+id/splashscreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/loading_circle"
android:layout_gravity="center"
/>
Just declare splash globally and not in oncreate().
i think you need to add visibility :gone in XML:ImageView
and make imageview INVISIBLE
You need to add
a.setFillAfter(true);
to the end of your code inside your Runnable.

Background TransitionDrawable not redrawing on some devices

I'm using a TransitionDrawable two go between two GradientDrawables, and I'm setting that as the background drawable of a Button. This works fine transitioning between two ColorDrawables, but when I try doing it with GradientDrawables I get some very strange results.
On my 2.3.5 device everything works peachy.
On my 4.2.2 device, the buttons just takes on the first gradient and don't redraw at all.
If I add a call to view.refreshDrawableState() or view.setBackgroundDrawable(drawable) after I've started the transition, it will refresh but things get even weirder:
some buttons work correctly
some buttons flicker at points during the transition
one button, for whatever reason, transitions to black instead of to the second gradient drawable
I am looping the transition with a recursive post to the view, but I don't think that's problem because I get the same problems when I don't do it.
Does anyone know what I can do to fix this? Here's the relevant code:
private static void highlightView(View view, Context context) {
TransitionDrawable drawable;
GradientDrawable d1 = new GradientDrawable(Orientation.TOP_BOTTOM, new int[] { HIGHLIGHT_COLOR_1, HIGHLIGHT_COLOR_G1 });
d1.setCornerRadius(3f);
GradientDrawable d2 = new GradientDrawable(Orientation.TOP_BOTTOM,
new int[] { HIGHLIGHT_COLOR_2, HIGHLIGHT_COLOR_G2 });
d2.setCornerRadius(3f);
drawable = new TransitionDrawable(new Drawable[] {
d1,
d2
});
view.setBackgroundDrawable(drawable);
drawable.setCrossFadeEnabled(true);
animateBackground(drawable, true, view);
}
private static void animateBackground(final TransitionDrawable drawable,
final boolean forward, final View view) {
if (view.getBackground() != drawable) return;
if (forward) {
drawable.startTransition(HIGHLIGHT_CYCLE / 2);
} else {
drawable.reverseTransition(HIGHLIGHT_CYCLE / 2);
}
view.postDelayed(new Runnable() {
#Override
public void run() {
animateBackground(drawable, !forward, view);
}
}, HIGHLIGHT_CYCLE / 2);
view.refreshDrawableState(); //without this, no transition occurs at all
}

Categories

Resources