Animating crossfade between 2 layouts - java

I'm trying to implement an animation which crossfades between 2 layout, with a layover between them. The first layout is the main layout, the second is a simple linear layout with textView and red background (your classic "Wrong!" screen if you will...). My goal is to animate a quick transition between the mainLayout and wrongLayout, have the program wait for a short period of time while displaying the wrongLayout and then automatically return to mainLayout. This turns out to be extremelly hard, I've tried using monitors, Thread.sleep() etc. but what I get is that the program waits before starting the animation and THEN performs it without any layover.
My code is as follows:
In the main method-
LinearLayout wrongLayout = (LinearLayout) findViewById(R.id.wrong_layout);
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_layout);
int animationDuration = getResources().getInteger(
android.R.integer.config_longAnimTime);
crossfade(wrongLayout, mainLayout, animationDuration);
/* This is where I want it to wait for 1 second */
crossfade(mainLayout, wrongLayout, animationDuration);
and the crossfade method-
private void crossfade(View fadeInLayout, final View fadeOutLayout,
int animationDuration) {
// Set the content view to 0% opacity but visible, so that it is visible
// (but fully transparent) during the animation.
fadeInLayout.setAlpha(0f);
fadeInLayout.setVisibility(View.VISIBLE);
// Animate the content view to 100% opacity, and clear any animation
// listener set on the view.
fadeInLayout.animate()
.alpha(1f)
.setDuration(animationDuration)
.setListener(null);
// Animate the loading view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't
// participate in layout passes, etc.)
fadeOutLayout.animate()
.alpha(0f)
.setDuration(animationDuration)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fadeOutLayout.setVisibility(View.GONE);
}
});
}
Thanks a lot...

Ok, so I've found this post which deals with just about the same problem-
Why the Sleep executes first and than the code above it in android?
I've changed the appropriate execution function and now it seems to work properly, though I'm still puzzled by the fact that I cannot cause the code to stop at a designated location for a specific amount of time. Oh well...

Related

Animation bag with some ImageViews

I have problem with my android animation. When I click the first time on my ImageView, my image have a rotation but when click the second time on my ImageView, rotation don't work. Why is it happened?
My rotation method in Java code:
private boolean tomIsInvisible = false;
public void eraseTom(View view) {
ImageView tom = findViewById(R.id.tom);
ImageView jerry = findViewById(R.id.jerry);
if (tomIsInvisible) {
tom.animate()
.rotation(3600)
.scaleX(1)
.scaleY(1)
.alpha(1)
.setDuration(3000);
jerry.animate()
.rotation(3600)
.scaleX(0)
.scaleY(0)
.alpha(0)
.setDuration(3000);
tomIsInvisible = false;
} else if(!tomIsInvisible) {
tom.animate()
.rotation(3600)
.scaleX(0)
.scaleY(0)
.alpha(0)
.setDuration(3000);
jerry.animate()
.rotation(3600)
.alpha(1)
.scaleX(1)
.scaleY(1)
.setDuration(3000);
tomIsInvisible = true;
}
}
Others methods on my ImageView work correctly.
When you call rotation(3600) first time it animates rotation from 0 to 3600. (default view rotation is 0). After first animation rotation is 3600 (ViewPropertyAnimator changes actual value of property while it animate things). So when you call rotation(3600) second time rotation of your view is already 3600 and you try to animate it to 3600. Thats why there is no visual changes. There is rotationBy method which apply specified value to view rotation, try to use it.
view.animate().rotationBy(3600)
Another solution is to animate from 0 to 360 and in the animation end reset view rotation to 0.

ListView (Inside CardView) visually bugs upon resizing. Gif inside

FIXED: I was incorrectly updating my ListView adapter. see: How to refresh Android listview?
I have been struggling with an incredibly weird bug for too long of a time, and I wonder if any of you have had similar problems.
A detailed explanation of the bug will be less clear than for me to just show you, so I have attached a gif that displays exactly what goes wrong below.
http://giphy.com/gifs/xT9DPGixQnDIEHlVU4
Question 5 is included to show you how things are supposed to wrong. Then, when the CardView and the ListView inside it resize because the amount of options changes at question 6, the following goes wrong:
- The colors of the listview items do not get updated according to their correctness. (should be either green or a light shade of red)
- The checked RadioButton weirdly gets unchecked, right before I click the button.
Note: this bug only appears once upon resizing of the Listview. Everything proceeds to work fine once a similar size optionlist is supplied at the next question
These actions take place upon the second click of the button, which calls the following code
/*
FOR EACH LISTITEM:
> Make button unclickable
> Animate background change according to correctness of answer
*/
for (int i = 0; i < currentQuestion.getOptionList().size(); i++) {
ListView optionList = (ListView) rootView.findViewById(R.id.optionList);
View item = (View) optionList.getChildAt(i);
item.findViewById(R.id.optionRadioButton).setClickable(false);
final LinearLayout llayout = (LinearLayout) item.findViewById(R.id.itemLinearLayout);
int colorTo = getResources().getColor(R.color.lightPrimary);
if (currentQuestion.getOptionList().get(i).equals(currentQuestion.getAnswer())) {
colorTo = getResources().getColor(R.color.correct);
}
int colorFrom = getResources().getColor(R.color.white);
ValueAnimator colorAnimation = backgroundColorAnimator(
colorFrom,
colorTo,
llayout,
i);
colorAnimation.start();
}
// Bottom part of list view is animated SEPERATELY.
// please note that THIS DOES GET UPDATED ACCORDINGLY.
int colorFrom = getResources().getColor(R.color.white);
int colorTo = getResources().getColor(R.color.lightPrimary);
// Also increments question correct counter (important
if (correctAnswerSelected) {
colorTo = getResources().getColor(R.color.correct);
currentExercise.questionCorrectlyAnswered();
}
ValueAnimator anim = backgroundColorAnimator(
colorFrom,
colorTo,
fabContainer,currentQuestion.getOptionList().size()+1);
anim.start();
My hypothesis: Somehow, upon resizing the CardView / RelativeLayout / ListView, the ListView gets reinitiated and I call a different version of it. I suspect this is the cause because the lower part of the CardView (a FAB within a FrameLayout) does change color accordingly.
Any and all help is appreciated, I am at a complete loss with this question
Thanks in advance.

Occasional flickering between ImageViews when moved

I have a series of ImageViews that I programatically added into a LinearLayout, so they all end up horizontally lined up.
But when I try to use a TranslateAnimation to move all the images at once, a 1 pixel white gap flashes between every ImageView for about .02 seconds and then disappears. And this seems to consistently happen every 2 seconds or so.
TranslateAnimation moveLeft = new TranslateAnimation(0, -1250, 0, 0);
moveLeft.setDuration(10000);
moveLeft.setFillAfter(true);
I make my ImageViews all at the same time before I move them. (Also, the ImageViews have all default settings) I've also confirmed that there are no white gaps between the ImageViews before I move them.
The flickering only happens when I set all the ImageViews's animations to moveLeft.
Also, here is the class in question :
public class Terrain {
Bitmap tile;
InputStream is;
ImageView imageViewPlatform;
Drawable tileDrawable;
ArrayList<ImageView> terrainArray = new ArrayList<ImageView>();
ArrayList<TranslateAnimation> moveLeftArray = new ArrayList<TranslateAnimation>();
int count = 0;
int terrainBlockNumber = 0;
boolean initialized = false;
TranslateAnimation moveLeft;
public void initialize(Activity activity){
is = activity.getResources().openRawResource(+R.drawable.game_tile);
tile = BitmapFactory.decodeStream(is);
tileDrawable = new BitmapDrawable(activity.getResources(), tile);
moveLeft = new TranslateAnimation(0, -1250, 0, 0);
moveLeft.setDuration(10000);
moveLeft.setFillAfter(true);
initialized = true;
Log.d("Terrain", "Terrain images are initialized.");
}
public void draw(Activity activity, LinearLayout linearLayout,
LinearLayout.LayoutParams layoutParams) {
if (!initialized) {
throw new RuntimeException("initialize() method must " +
"be called before the draw() method.");
}else{
terrainArray.add(new ImageView(activity));
++count;
terrainArray.get(count-1).setImageDrawable(tileDrawable);
linearLayout.addView(terrainArray.get(count-1), layoutParams);
}
}
public void move(Activity activity) {
terrainBlockNumber++;
final int terrainAnimationBlock = terrainBlockNumber;
moveLeft.setAnimationListener(new Animation.AnimationListener() {
int currentCount = terrainAnimationBlock;
#Override
public void onAnimationStart(Animation animation) {
Log.d("Animation Started", "Block Number is " + currentCount);
}
#Override
public void onAnimationEnd(Animation animation) {
terrainArray.get(currentCount - 1).setVisibility(View.GONE);
Log.d("Terrain Deletion", "Block number " +
currentCount + " has been deleted.");
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
terrainArray.get(terrainBlockNumber - 1).startAnimation(moveLeft);
}
}
}
This is the XML file for the activity
<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"
tools:context="com.example.project.PlayActivity">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/linearLayout"
android:weightSum="1"
android:layout_alignParentTop="true"
android:layout_marginTop="200dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
</LinearLayout>
</RelativeLayout>
UPDATE :
Moving the entire LinearLayout does not seem to work either. Although, moving the entire LinearLayout isn't really helpful. It cuts off ImageViews that are off-screen.
But since you requested it, all I did was change the move method to :
public void move(LinearLayout linearLayout){
linearLayout.setAnimation(moveLeft);
}
All the images did actually move at the same speed, and there is still the flickering between the images.
UPDATE 2
I have confirmed that it has something to do with my images/how they're formatted/the size of the images or something along those lines.
If it is any help, the image I use is 95 X 84 pixels. (It's really tiny)
If you have several images you might want to:
Use a RecyclerView. This gives you more control over animations and decorations, and optimizes the memory usage at the same time. This answer will help you understand how to make your animations.
Make sure you are not constantly resizing your images. If the animation needs to handle images that are originally too big, it might impact on the quality of the animation (i.e. use thumbnails and fixed sizes in order to avoid costly computations)
For instance, if your original images are 600x800 but your image
view has a centerCrop/fit/etc ending up occupying a space of 200x200,
android will be doing a lot of resizing to match those settings. The
more computations it does, the more chances you get of missing
frames. In other words: what you experience is a low framerate,
which happens when android is unable to finish all drawing
computations in time for the next screen refresh.
There are different problems you can attack:
Reduce the computations by using the right image sizes
Smaller images also mean less memory usage, which reduces the need of memory reallocation or forced garbage collection.
Avoid computing/rendering things that are invisible. Either because they are out of screen or because something overlaps them. In your case, recycler view might help to load only the images on your visible screen, instead of wasting space and computations on images that are out of sight at the moment.
Reduce the layout rewrite. Android tries to render only the sections with updates, instead of re-render all the screen. But if your layout forces other layouts to recalculate their size, you can end up forcing a whole resize. In your case, do not use LinearLayout to list images. Instead, use some layout that is actually designed for that sort of things. As I said, RecyclerView with the default LinearLayoutManager works very well.
Check if you have hardware acceleration turned on.
Try to put the ImageViews in a LinearLayout or other ViewGroup and animate the entire ViewGroup and see if that helps.

Focus ScrollView to selected position programmatically - Android

I have a ScrollView with a lot buttons. Each button is enabled when the user unlocks that button/level. I would like to focus the ScrollView on the latest unlocked button/level. See the screenshot below.
I found some functions like scrollTo() that could focus the ScrollView either at top, button or something like that but I would like to focus the ScrollView at certain places like the button ID that says Level 8 in the screenshot below. How would I go about doing this?
I think this should be good enough :
yourButtonView.getParent().requestChildFocus(yourButtonView,yourButtonView);
public void RequestChildFocus (View child, View focused)
child - The child of this ViewParent that wants focus. This view will contain the focused view. It is not necessarily the view that actually has focus.
focused - The view that is a descendant of child that actually has focus
First you need to know the position of item in scroll that has to get focus once you know that you can use following code to make that item focus
final int x;
final int y;
x = rowview[pos].getLeft();
y = rowView[pos].getTop();
yourScrollView.scrollTo(x, y);
refer this question
I agree with the benefits of previous answers. However, by experience, I have found this to be more complex than this. The setSelectionFromTop is very sensitive and often breaks if it is executed too early. This may depend on different reasons but the two primary reasons are that
If executed from within Activity lifecycle methods the views have not been loaded/configured yet.
View modifications triggered after the list move action seems to break the move. Probably overwriting some value before the move has been finalized due to a recalculation of the views.
The reasoning seems to apply for both setSelectionFromTop and setSelection() methods although
I tested mostly with setSelectionFromTop. smoothScrollToPosition() seems to be more robust, probably because it by definition changes the list position delayed whn doing the smooth scrolling.
Look at this example source code:
// Wee need to pospone the list move until all other view setup activities are finished
list.post(new Runnable(){
#override
public void run() {
list.setSelectionFromTop(selectedPosition, Math.max(0, Math.round(list.getHeight() / 3))); // Make sure selection is in middle of page, if possible.
// Make sure you do not modify (this or other) parts of the view afterwards - it may break the list move
// activityButtons.setVisibility(View.GONE);
}});
see: http://developer.android.com/reference/android/widget/ListView.html#setSelectionFromTop(int, int)
'int selectedLevel' holds the currently selected level, information is held in a Level class.
'values' is a list with all your levels, displayed by the list.
Example:
ListView lv = (ListView)findViewById(android.R.id.list);
int i = 0;
for (Level l : values) {
i++;
if (l.level == selectedLevel) {
lv.setSelectionFromTop(i, 200);
break;
}
}
try this
sc.post(new Runnable() {
public void run() {
sc.smoothScrollTo(x, y);
}
});
x the position where to scroll on the X axis
y the position where to scroll on the Y axis
Use this code, taken from this answer
private final void focusOnView(){
new Handler().post(new Runnable() {
#Override
public void run() {
your_scrollview.scrollTo(0, your_EditBox.getBottom());
}
});
}
Use this code, taken from my another answer
scrollViewSignup.post(new Runnable() {
#Override
public void run() {
int scrollY = scrollViewSignup.getScrollY();
scrollViewSignup.scrollTo(0, 0);
final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
view.requestRectangleOnScreen(rect, true);
int new_scrollY = scrollViewSignup.getScrollY();
scrollViewSignup.scrollTo(0, scrollY);
scrollViewSignup.smoothScrollTo(0, new_scrollY);
}
});
This code tries to smooth scroll and uses the standard behaviour of system to position to an item. You can simply change smoothScrollTo with scrollTo if you don't want the system to smooth scroll to the item. Or, you can use the code below only.
scrollViewSignup.post(new Runnable() {
#Override
public void run() {
scrollViewSignup.scrollTo(0, 0);
final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
view.requestRectangleOnScreen(rect, true);
}
});
Use the desired code block after trying, or, according to the need.

Setting height, and width of a relative layout in android

Here is my scenario.
I have an image which is made as per resolution 320*480 (assuming i am using mdpi mobile). I am adding this image as a background to a relative layout.
Now my screen has three main things.
1- Title bar (The standard title bar of android)
2- My relative layout and its sub view image relative layout which is matched parent.
3- My menu bar at the bottom.
Now since my image is getting stretched in between menu bar and title bar. I want to make it fit the screen. Below is the code I am using.
mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout()
{
if (notCreated == true)
{
notCreated = false;
}
else
{
mnHeight = mainLayout.getHeight();
Rect rect = getRawCoordinatesRect(mainLayout);
h = getWindowManager().getDefaultDisplay().getHeight() -
- rect.top - mainLayout.getHeight();
// rect.top to remove android standard title bar
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(image.getWidth(),LayoutParams.MATCH_PARENT);
params.topMargin = -1 * rect.top;
params.bottomMargin = -1 * h;
image.setLayoutParams(params);
}
}
});
Now this is not working. A little help would be appreciated.
Note: Actually I just want to stretch my image relative layout to 320*480. Right now it is sandwitched between title bar and my menu bar. E.g right now its dimensions are 320*400
Not sure if it will help, but try to play with setScaleType() trying different options.
image.setScaleType(ScaleType.FIT_CENTER);
Here are listed all the constans the ScaleType class has.
I must be honest and say i'm not completely sure what you want to do here. But i'm going to assume that you want to make the image function as a background..
If that's what you want, you can do this simply by setting the android:background="#drawable/your_image" attribute on the main layout in your layout file.
If what you want is remove the titlebar, this is done pretty simple by adding this line to your onCreate method in your activity class:
//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
If what you want to do is remove the notificationbar, this is also done in the onCreate method in your activity class:
//Remove notification bar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
I hope this can help you :-) If it's not what you're looking for, then dont hesitate from trying to reformulate what you want.

Categories

Resources