Colors "flowing" in Android background - android

I have an application and I want to set it's background just like the Instagram's login page, the one with that "gradient colors". The colors are "moving" and it creats a cool effect. This is what I've tried so far:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_take_one);
colorFul = (RelativeLayout) findViewById(R.id.background);
GradientDrawable gd = new GradientDrawable(GradientDrawable.Orientation.TL_BR, new int[] {a,b});
gd.setCornerRadius(0f);
colorFul.setBackgroundDrawable(gd);
for(int i = 0; i<6; i++){
if(a == 0xff000000){
a = 0xff00ffff;
b = 0xff444444;
}else if(a == 0xff00ffff){
a = 0xff888888;
b = 0xff00ff00;
}else if(a == 0xff888888){
a = 0xffcccccc;
b = 0xffff00ff;
}else if(a==0xffcccccc){
a = 0xffff0000;
b = 0xffffffff;
}else if(a==0xffff0000){
a = 0xffffffff;
b = 0xffffff00;
}
System.out.println("||");
SystemClock.sleep(1000);
System.out.println(">");
}
}
But this doesn't work. What happens is that the collors don't change, it remains black until it gets to the last if and then the background become white and yellow(that are, respectively, the collors 0xffffffff and 0xffffff00), in gradient shape.
So, how can I do it? I don't care how it's done. Whether it is with GradientDrawable or using an animated gif as background(which didn't work, the gif remained still) or any other way. Thanks.
(This is what I want, the gif isn't that good but you can see how the background is changing it's color)

You could programmatically create something that changes the level of gradient over time, but that would require some effort. Alternatively, you could use a TransitionDrawable to fade between different gradients, which should produce a similar effect.
This can be implemented as follows:
<?xml version="1.0" encoding="UTF-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<!-- use two gradients, extending from opposite sides of the page-->
<item android:drawable="#drawable/gradientLeft" />
<item android:drawable="#drawable/gradientRight" />
</transition>
Then, you can activate the transition in code as follows:
TransitionDrawable transition = (TransitionDrawable) myLayout.getBackground();
transition.startTransition(1500);
Obviously you'll probably need to spend some time to get it looking the way you want, but this would be far easier than hard-coding a transitional algorithm!
COMPLETE AND WORKING CODE BELOW
So, I got my idea implemented, and it looks awesome! I didn't expect it would look this nice, but it's really cool. I was bored so decided I would shove the whole thing into a function so it's easier for you (and others) to utilize.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView image = (ImageView) findViewById(R.id.background);
Drawable backgrounds[] = new Drawable[3];
backgrounds[0] = ContextCompat.getDrawable(this, R.drawable.gradient1);
backgrounds[1] = ContextCompat.getDrawable(this, R.drawable.gradient2);
backgrounds[2] = ContextCompat.getDrawable(this, R.drawable.gradient3);
Crossfade(image, backgrounds, 10000);
}
public void Crossfade(final ImageView image, final Drawable layers[], final int speedInMs) {
class BackgroundGradientThread implements Runnable {
Context mainContext;
TransitionDrawable crossFader;
boolean first = true;
BackgroundGradientThread(Context c) {
mainContext = c;
}
public void run() {
Handler mHandler = new Handler(mainContext.getMainLooper());
boolean reverse = false;
while (true) {
if (!reverse) {
for (int i = 0; i < layers.length - 1; i++) {
Drawable tLayers[] = new Drawable[2];
tLayers[0] = layers[i];
tLayers[1] = layers[i + 1];
final TransitionDrawable tCrossFader = new TransitionDrawable(tLayers);
tCrossFader.setCrossFadeEnabled(true);
Runnable transitionRunnable = new Runnable() {
#Override
public void run() {
image.setImageDrawable(tCrossFader);
tCrossFader.startTransition(speedInMs);
}
};
mHandler.post(transitionRunnable);
try {
Thread.sleep(speedInMs);
} catch (Exception e) {
}
}
reverse = true;
}
else if (reverse) {
for (int i = layers.length - 1; i > 0; i--) {
Drawable tLayers[] = new Drawable[2];
tLayers[0] = layers[i];
tLayers[1] = layers[i - 1];
final TransitionDrawable tCrossFader = new TransitionDrawable(tLayers);
tCrossFader.setCrossFadeEnabled(true);
Runnable transitionRunnable = new Runnable() {
#Override
public void run() {
image.setImageDrawable(tCrossFader);
tCrossFader.startTransition(speedInMs);
}
};
mHandler.post(transitionRunnable);
try {
Thread.sleep(speedInMs);
} catch (Exception e) {
}
}
reverse = false;
}
}
}
}
Thread backgroundThread = new Thread(new BackgroundGradientThread(this));
backgroundThread.start();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<ImageView android:id="#+id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/gradient2"
android:scaleType="fitXY"/>
<TextView android:text="Hello World!" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
gradient1/2.jpg
The primary function here creates a new thread that will automatically begin shifting the two images back and forth. Once one full transition has completed, it will then begin to fade back into the original image. It creates a really smooth and flowy effect most of the time, but may look weird when combining some gradient drawables. The function looks like this:
public void Crossfade(final ImageView image, final Drawable layers[], final int speedInMs)
1) final ImageView image
The first parameter should be the image object that is going to represent your background.
2) final Drawable layers[]
The second parameter takes an array of drawables, which should be two images like the ones I showed above. Playing around with different gradient images is fun, and quite interesting to watch how colors "flow". Be careful with your image sizes, though, as I had initially used massive images that had crashed the app or stuttered terribly in the animation process.
3) final int speedInMs
The last parameter simply represents the time (in milliseconds) it will take to completely transition from the first drawable to the second.
Here's a GIF of the result of these two images crossfading with a speed of 5000ms (note: I couldn't put a 10 second GIF on here showing the whole transition, but it's quite smooth!):
Github Link To Repository
EDIT 2: I updated the Github and the function on here, but I just added in multi-drawable support so an array of any number of images can be added in and it will cycle through them chronologically, until reaching the end at which point it will reverse through and repeat. Sexy.

Related

Animation on image resource change

I am trying to change repeatedly images in image view (it doesn't matter what component to use). I need to change background image each N seconds.
I have tried to use Animation drawable declaring images in xml file.
It works, but I don't know to apply any effect to it, like fade in,blur or something other.
So my task is to change periodically background image with transition effect.
Please suggest how to deal with this problem, I would be very grateful for any help.
I used an image switcher to switch images in regular intervals
xml part
<ImageSwitcher
android:id="#+id/smsimg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/defaultimage" />
class code was like this
private final int[] images = { R.drawable.vava, R.drawable.vavaone,R.drawable.vavatwo,R.drawable.vavathree,R.drawable.vavafour,
};
#Override
protected void onCreate(Bundle savedInstanceState) {
img=(ImageSwitcher)findViewById(R.id.smsimg);
startAnimatedBackground();
private void startAnimatedBackground() {
Animation aniIn = AnimationUtils.loadAnimation(this,
android.R.anim.fade_in);
aniIn.setDuration(3000);
Animation aniOut = AnimationUtils.loadAnimation(this,
android.R.anim.fade_out);
aniOut.setDuration(3000);
final ImageSwitcher imageSwitcher = (ImageSwitcher) findViewById(R.id.smsimg);
imageSwitcher.setInAnimation(aniIn);
imageSwitcher.setOutAnimation(aniOut);
imageSwitcher.setFactory(this);
imageSwitcher.setImageResource(images[index]);
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
if (isRunning) {
index++;
index = index % images.length;
Log.d("Intro Screen", "Change Image " + index);
imageSwitcher.setImageResource(images[index]);
handler.postDelayed(this, interval);
}
}
};
handler.postDelayed(runnable, interval);
}

Changing background image periodically ImageView

I have layout FrameLayout as a root layout.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="#+id/background_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/init_image"
android:scaleType="centerCrop">
</ImageView>
......
......
</FrameLayout>
I need to change periodically some amount of images in a infinity loop (some condition) so like slideshow.
I have tried to use Handler but when I change I get OutOfMemory error.
I also tried ImageSwitcher but It seems not to work correctly.
Please give an example or advice how to implement it correctly following all design patterns of Android, thx.
Hye there , i was recently searching for this issue and came across a good solution as it doesn't apply automatic density based scaling of the images and use them as they are.
1- Put all your images in res/drawable-nodpi folder, you have to create this folder as it doesn't exist.
2 - Make them automatically change from one to other in an infinite loop.
int images[] = { R.drawable.background_1,
R.drawable.background_2,
R.drawable.background_3,
R.drawable.background_4,
R.drawable.background_5,
R.drawable.background_6,
R.drawable.background_7 }; // i've these images in **res/drawable-nodpi**
Here is the onCreate method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.imageView_Animated);
handler.postDelayed(changeImage, 5000); // after every 5secs it will change image.
}
Now here comes the part which handles all changing of images , outside onCreate do this.
Runnable changeImage = new Runnable() {
#Override
public void run() {
if (count >6) {
handler.removeCallbacks(changeImage);
} else {
if (count >= 6)
count = 0;
AlphaAnimation animation1 = new AlphaAnimation(0.5f, 1.0f); //here is a bit of animation for ya ;)
animation1.setDuration(5000);
animation1.setStartOffset(1300); //time for that color effect
animation1.setFillAfter(true);
imageView.startAnimation(animation1);
imageView.setBackgroundResource(images[count++]);
handler.postDelayed(changeImage, 5000);
}
}
};
All done, hope i helped you.

Gridview randomly failing to update properly on first load, remains incorrect until it's destroyed

I have a 2x27 gridview that's holding white imageviews. I then apply a colorfilter to the imageviews, and every cycle invalidate them. The end result is some animated colors moving around the gridview.
I'm having problems with the gridview randomly showing a white square, instead of the black I initalize everything to. Then, as the colors change every imageview updates, except for the ones that failed to load properly the first time. They always remain white.
Sometimes this doesn't happen. Sometimes it's 1 square, sometimes it's 4 squares.
If I rotate my screen, the stuck white ones go away and everything works. They never come back no matter how many times I rotate/leave the activity and return.
This is me updating the colorfilters. I've checked in here that every grid is getting updated, nothing remains white.
public void updateColors() {
Runnable runnable1 = new Runnable() {
#Override
public void run() {
int r = 0;
int g = 0;
int b = 0;
int y = 0;
while(keepRunning == true){
y = 0;
for(int x=0;x<Consts.VIEWCOUNT;x++){
g = Buffers.offLineBuffer_[y++];
r = Buffers.offLineBuffer_[y++];
b = Buffers.offLineBuffer_[y++];
Drawable myIcon = getResources().getDrawable( ImageAdapter.mThumbIds[x]);
myIcon.setColorFilter(new PorterDuffColorFilter(Color.rgb(r, g, b),PorterDuff.Mode.MULTIPLY));
}
try {
Thread.sleep(55);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
gridView.invalidateViews();
}
});
}
}
};
new Thread(runnable1).start();
}
This is my adapter
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(33, 33));
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
mThumbsID is just a list of ID's to drawables like below (I shortened it)
public static Integer[] mThumbIdsTemp = {
R.drawable.image1,
R.drawable.image2,
R.drawable.image3,
R.drawable.image4,
}
It just started doing this one day, I haven't been able to track it back to what is causing it, or why it's only ever on the first time it's loaded, but will remain until it's destroyed via rotating the screen.
I've lost over a day trying to track this down, and I'm lost as to what might be causing it.
Any ideas?

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
}

A reference to pojo in Android is lost during onClick event

I'm developing a small game where I have images that changes and a control panel (some buttons) which the user suppose to press them according to the shown image. The GameView class extends SurfaceView so when the activity starts it just create the game and set the content view (a layout with SurfaceView and some buttons in relative layout). The game call loadGameObjects during setSurfaceSize callback as follow:
public void setSurfaceSize(int width, int height)
{
synchronized (holder)
{
canvasWidth = width;
canvasHeight = height;
GameView.this.postInvalidate();
loadGameObjects(getResources());
}
}
In loadGameObjects method i keep a reference to a game pojo object which is not a view (but holds references to images) as follow:
public void loadGameObjects(Resources resouces)
{
List<GameObject> gameObjects = new LinkedList<GameObject>();
int middleX = getWidth()/2;
int middleY = getHeight()/2;
//Create the backgroung game object
BitmapDrawable background = (BitmapDrawable)resouces.getDrawable(R.drawable.g_monitor);
Bitmap bitmap = Bitmap.createScaledBitmap(background.getBitmap(), getWidth(),
getHeight(), true);
background = new BitmapDrawable(bitmap);
gameObjects.add(new GameObject(this, getContext(), background, new Point(0,0)));
//Create the game object with all its images.
Map<RunningGoblinResourceEnum, BitmapDrawable> goblinImgs = new HashMap<RunningGoblinResourceEnum, BitmapDrawable>();
goblinImgs.put(RunningGoblinResourceEnum.greenGoblinUp, (BitmapDrawable)resouces.getDrawable(R.drawable.goblin_up_green));
//This map get more entries like this...
//ourGoblin is a member var that later will be null in onClick
ourGoblin = new RunningGoblinObject(this, getContext(), goblinImgs,
new Point(middleX, middleY));
gameObjects.add(ourGoblin);
setGameObjects(gameObjects);
}
During doDraw the game objects "draw" method is called to draw themself on the canvas.
My problem is that when I click the button the reference to ourGoblin game object is null although it was valid during loadGameObjects method.
Can someone please tell me what I'm missing?
I had something simillar.
In loadGameObjects method you create ourGoblin instance using the new operator. However, if this is a view in a layout which was used with setContentView the system does not relate your view to the view in the layout and thus from the system point of view the view in the layout is still null until findViewById will be called with this view id. Try to call findViewById on that id and see if ourGoblin is still null, if not then take in mind that you still have two instances of that object, one created using the new operator and one by the system.
Sure,
You can see that it is a very simple and straight forward onClick implementation:
public void onClick(View v)
{
Log.d(getClass().getName() + "onClick", "ourGoblin = " + ourGoblin);
if(ourGoblin == null)
return;
Log.d(getClass().getName() + "onClick", "ourGoblin = " + ourGoblin.getCurrentImageEnum().toString());
int id = v.getId();
switch(id)
{
case R.id.greenUp:
if(RunningGoblinResourceEnum.greenGoblinUp.equals(ourGoblin.getCurrentImageEnum()))
{
//Do something to statistics
}
break;
}
}
and also my layout xml file is as follow:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gameFrame"
android:layout_width="match_parent" android:layout_height="match_parent">
<com.test.game.GameView android:id="#+id/gameView"
android:layout_width="match_parent" android:layout_height="match_parent" />
<RelativeLayout android:id="#+id/controlPanel"
android:layout_width="match_parent" android:layout_height="match_parent">
<Button android:id="#+id/greenUp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_centerInParent="true"
android:text="up"/>
</RelativeLayout>
</FrameLayout>

Categories

Resources