Animate multiple views using the same Animation - java

I have a simple animator file:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/accelerate_decelerate_interpolator"
android:ordering="sequentially" >
<objectAnimator
android:duration="1000"
android:propertyName="x"
android:repeatCount="1"
android:repeatMode="reverse"
android:valueTo="-50"
android:valueType="floatType" />
Basically this takes a component and slides it along the X-axis by 50dp to the left. I've successfully attached this to ONE component, and it works flawlessly, but when I try to attach it to multiple components at once, the animation only works for the final component.
For Example:
I have 5 cards. The AI enemy picks a random card from it's hand. But I would like to animate the enemy "picking" the card. This is where the animation comes into play.
So something like this:
AnimatorSet cardSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.pick_card);
for(int i=0; i<enemyCards.size(); i++){
cardSet.setTarget(enemyCards.get(i));
cardSet.start();
}
The goal here, would be to loop through each card in the array and slide it out on the X axis. But the animation only occurs on the final card (the 5th card in the array)
Additionally (THIS IS BOLD FOR A REASON, people do not read large paragraphs anymore, and someone keeps editing my formatting) - I would like to have a delay each time the card slides out. So the loop should be something like:
loop{
animate card 1
delay
}
OR
the animator file should be something like
android:delay="100"
Ive been trying with little success

You can collect your views in some viewgroup and than animate just parent view so all child views animated ?

This a sketch code written in text editor, it may have syntax errors, but you'll get the concept:
AnimatorSet cardSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.anim.pick_card);
List<AnimatorSet> animators = new ArrayList<>(enemyCards.size());
for (int i = 0, size = animators.size(); i < size; ++i) {
animators.add(cardSet.clone());
}
final int step = 100;
int delay = 0;
for (int i = 0, size = enemyCards.size(); i < size; ++i) {
AnimatorSet set = animators.get(i);
set.setTarget(enemyCards.get(i));
set.setStartDelay(delay);
delay += step;
set.start();
}

Related

Can Android Studio remove multiple elements from an array? How?

I'm practice developing an app but I met a problem. I want remove two elements from an array but android studio only can remove one and if I adding one more the app will crash, below is my code and now I only put one code to remove the first element and i need to remove last element otherwise the choice for answer will mix the array.
ArrayList<ArrayList<String>> quizArray = new ArrayList<>();
String quizData[][] = {
{"quadrilateral","quadrilateral","triangle","heptagon","pentagon","hexagon","decagon","Which one is the green polygon just now ?"},
{"triangle","triangle","heptagon","quadrilateral","pentagon","octagon","decagon","Which one is the red polygon just now ?"},
{"circle","circle","triangle","quadrilateral","pentagon","nonagon","decagon","Which one is the black polygon just now ?"},
{"star","star","circle","octagon","pentagon","hexagon","decagon","Which one is the brown polygon just now ?"},
{"decagon","decagon","triangle","circle","pentagon","hexagon","star","Which one is the pink polygon just now ?"},
{"heptagon","heptagon","decagon","quadrilateral","pentagon","hexagon","star","Which one is the yellow polygon just now ?"},
{"hexagon","hexagon","decagon","heptagon","pentagon","octagon","star","Which one is the sky blue polygon just now ?"},
{"nonagon","nonagon","circle","quadrilateral","triangle","hexagon","star","Which one is the orange polygon just now ?"},
{"pentagon","pentagon","nonagon","octagon","heptagon","hexagon","circle","Which one is the purple polygon just now ?"},
{"octagon","octagon","triangle","quadrilateral","pentagon","hexagon","star","Which one is the dark blue polygon just now ?"}
};
public void Show_Next_Quiz(){
Random random = new Random();
int Random_Num = random.nextInt(quizArray.size());
ArrayList<String> quiz = quizArray.get(Random_Num);
Question1.setText(quiz.get(7));
iV1.setImageResource(
getResources().getIdentifier(quiz.get(0), "drawable", getPackageName())
);
iV2.setImageResource(
getResources().getIdentifier(quiz.get(0), "drawable", getPackageName())
);
iV3.setImageResource(
getResources().getIdentifier(quiz.get(0), "drawable", getPackageName())
);
iV4.setImageResource(
getResources().getIdentifier(quiz.get(0), "drawable", getPackageName())
);
iV5.setImageResource(
getResources().getIdentifier(quiz.get(0), "drawable", getPackageName())
);
iV6.setImageResource(
getResources().getIdentifier(quiz.get(0), "drawable", getPackageName())
);
Right_Answer = quiz.get(1);
quiz.remove(0);
//quiz.remove(7);
Collections.shuffle(quiz);
ans1.setText(quiz.get(1));
ans2.setText(quiz.get(2));
ans3.setText(quiz.get(3));
ans4.setText(quiz.get(4));
ans5.setText(quiz.get(5));
ans6.setText(quiz.get(6));
quizArray.remove(Random_Num);
}
Your program is crash because you're trying to remove an item from the List by using an incorrect item position.
For example, assume that you have an ArrayList with size of 7:
ArrayList<String> quizzes = new ArrayList<>(7);
the quiz items from quizzes will be in 0 - 6 range of index position. When you're removing the first item with:
quizzes.remove(0);
the quizzes size is now 6. Now you can only access the items from 0 to 5 index position. It will gives error when you're trying to remove an item with item position beyond that. So, the following code won't work and gives you a crash:
quizzes.remove(7);
because you're trying to access a non-exist item position.
So, you can't depends on the item position to remove the item in your case. You can use public boolean remove(Object o) instead.
quizzes.remove("triangle");
Probably what you need is an another ArrayList for ansX views to match the size of the questions. Something like this:
int sizeOfTheQuiz = 6;
ArrayList<String> quizzes = new ArrayList<>(sizeOfTheQuiz);
ArrayList<TextView> tvAnswers = new ArrayList<>();
tvAnswers.add(ans1);
tvAnswers.add(ans2);
tvAnswers.add(ans3);
tvAnswers.add(ans4);
tvAnswers.add(ans5);
tvAnswers.add(ans6);
// size of the quizzes must not larger than tvAnswers
for(int i = 0; i < quizzes.size(); i++) {
tvAnswers.get(i).setText(quizzes.get(i));
}

Android: How to add programmaticaly fixed size buttons without deformation in a layout?

I want to create a Card Deck app that contains (lets say) from 0 to 10 total cards as it runs.
I have a RelativeLayout created with XML inside a parent layout, this RelativeLayout has width to match parent and height to wrap content.
Now i want to add fixed size buttons (cards) to that layout and when the don't have room they must not deformate but be scaled and placed on top of the other.
When i just add them it happens this:https://postimg.org/image/ic8pmaju7/
But i want to achieve something like this :https://postimg.org/image/567dj49j9/
*For second image i used setmargins(xleft,x,x,x);...xleft++; , but when i have 2 or 5 buttons they keep being on the top of the other button, instead of just use the free space.
So im asking if there is a layout or a method that when there is no room (small screen or too many buttons) puts buttons on top and next of the other button than deforming them.
ConstraintLayout allows you to create large and complex layouts with a flat view hierarchy (no nested view groups). It's similar to RelativeLayout in that all views are laid out according to relationships between sibling views and the parent layout, but it's more flexible than RelativeLayout and easier to use with Android Studio's Layout Editor.
Using the ConstraintLayout you can do it, and spending less user processing than if you use nested LinearLayouts.
To put button next to button and adjust them in according to screen size, you can use the Chains, that is a resource of ConstraintLayout.
Chains provide group-like behavior in a single axis (horizontally or vertically). The other axis can be constrained independently.
Click here to read more about ConstraintLayout and Click here to read more about Chains.
Ok, guys i tryied what you suggested but i couldnt't achieve what i wanted, so i spent HOURS working on it and i ended up with some math and some help of fuctions to (at last) find the solution. I will post my code if someone wants to give a try:
public void ChangeView(View view) {
//here we put number of cards that we want to be scaled and displayed (cards=buttons)
int CardMax=13;//13 for example!!!
//getting scale for dpi of phone screen(i think??)
final float scale = getResources().getDisplayMetrics().density;
// getting some values we need to know
// **THESE VALUES DEPEND FROM SCREEN RESOLUTION OR THE SIZE OF BUTTON**
int layWidth = layout.getWidth(); //getting layout width that equals screen width(in pixels)
int btnWidth = (int) (50 * scale); //setting and scaling the width of the button for any screen
int maxLayfit=layWidth/btnWidth; //getting how many buttons can be added to layout without deformation
int layMidWidth = layWidth / 2; //getting layouts half width (that helps to start adding buttons from middle)
int StrMeasur; // this help how to start setting the buttons
if (CardMax <= maxLayfit) { // if cards are less than Layout can hold without deformation
StrMeasur = CardMax; // StrMeasur equals number of cards
} else {
StrMeasur = maxLayfit; // else equals max number of cards without deformation
}
int pointer=0; //pointer that will say where to put the first button
pointer = layMidWidth - ((btnWidth / 2) * StrMeasur);//depends of how many cards we have and button width
int start =layMidWidth-((btnWidth / 2) * StrMeasur);
int nextBtn = 0; //nextBtn says where to put the next button
//here we set the buttons on top and next to the previous button as we need **TRICKY PART**
if (CardMax > maxLayfit-1) { //if number of cards is bigger than the number the layout can hold
//then we calculate first card position (start/pointer) and the last card position(=layout width-button width)
//we find how many equal parts the layout has to be divided with the given cards
//and we get the width of the part to set it as pointer of the next card place
nextBtn =(((layWidth-start)-btnWidth)-start)/CardMax;
}else{
nextBtn=btnWidth; //else the pointer just set buttons next to the other
}
//Here we display all the buttons
for (int i = 0; i < CardMax; i++) {
Button cards = new Button(this);
cards.setWidth(btnWidth);
cards.setHeight((int) (90 * scale));
RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params2.setMargins(pointer, 0, 0, 0);
cards.setLayoutParams(params2);
cards.setText("" + (i + 1));
cards.setId(i);
layout.addView(cards);
pointer = pointer + nextBtn;
}
}
I belive it will work on any screen.

How do I change alpha of an image view multiple times using thread.sleep?

I am trying to create an animation for my game. I am trying to make an animation of a coin flip that will stop under certain conditions.
So far I have tried to change an image view multiple times within one method and using thread.sleep to delay the transition between the pictures.
Using 12 different images I am now trying to make it so the alpha of the first image will set to 0 and the second image will set to one, the the second image will set to 0 and the third will set to 1, etc...
The way I am currently trying to do it is by putting images inside of an array of ImageViews and then calling them sequentially.
setContentView(R.layout.coin_flip_screen);
for(int i = 0; i < 4; i++){
headsTails[i].animate().alpha(0).setDuration(100);
headsTails[i+1].animate().alpha(1).setDuration(100);
try {
Thread.sleep(100);
} catch (Exception e) {
}
}
final int size = imageView.length;
final int animTime = 300;
final Handler animationHandler = new Handler();
Runnable animationRunnable = new Runnable() {
int i = 0;
#Override
public void run() {
if(i == size-1){
animationHandler.removeCallbacks(this);
return;
}
imageView[i++].animate().alpha(0f).setDuration(animTime).start();
imageView[i].animate().alpha(1f).setDuration(animTime).start();
animationHandler.postDelayed(this, animTime);
}
};
animationHandler.post(animationRunnable);
This code will iterate through all your imageviews in the array and stop itself once all the images are consumed.
Play along with your animTime variable until you get the perfect animation effect. Ideally it should be around 300 to 500 ms.
I will personally not use array of imageviews to create this effect as
it will eat up the memory. There are many more efficient ways to do
the coin flip animation, which you can google when you get time.
This should fix it
headsTails[i].animate().alpha(0).setDuration(100).start();

How to make each ImageView of list to start animation one by one?

I'm new to Android and I have 9 ImageViews that I want to make transparent. I'm using AlphaAnimation to make them fade. They fade indeed but I want to make them fade one by one. Unfortunately they all fade together and I don't know why.
I tried to use various ways to do it(including CountDownTimer,Thread.sleep(),new Handler().postDelayed()), but there is no change. All of the ImageViews fade simultaneously, not one by one. I know they are capable of doing it because animation on one works, but iteration throught list of this views ends up with all of them being animated at the same time.
Important methods(I guess):
private void fadeImageTiles(List<ImageView> ivs) {
Collections.shuffle(ivs);
for (ImageView iv : ivs) {
//maybe there's problem with iteration?
gradientFade(iv);
}
}
private void gradientFade(ImageView iv){
AlphaAnimation animation = new AlphaAnimation(1f,0f);
animation.setDuration(2000);
iv.startAnimation(animation);
iv.setVisibility(View.INVISIBLE);
}
Final effect is to make them fade randomly revealing image behind
You can use void setStartOffset (long startOffset) to specify after how many milliseconds the view should be animated.
For example:
private void fadeImageTiles(List<ImageView> ivs) {
Collections.shuffle(ivs);
for (int i = 0; i < ivs.size(); i++) {
//maybe there's problem with iteration?
gradientFade(ivs.get(i), i);
}
}
private void gradientFade(ImageView iv, int index){
AlphaAnimation animation = new AlphaAnimation(1f,0f);
animation.setDuration(2000);
animation.setStartOffset(index * 500);
iv.startAnimation(animation);
iv.setVisibility(View.INVISIBLE);
}
Or you can use ViewPropertyAnimator without writing much code. Replace your code inside your gradientFade method with this:
iv.animate().alpha(0).setDuration(2000).setStartDelay(index * 500);

Avoid dynamic views from overlapping

I am developing an app that requires multiple buttons to be created dynamically (onCreate of MainActivity class). Each button has a dimension of 100x100dp.
Here's the code:
for (int i = 0; i < count; i++) {
buttons[i] = new Button(this);
RelativeLayout ll = (RelativeLayout)findViewById(R.id.maincontainer);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
buttons[i].setY(i * 150); // should be random
buttons[i].setX(i * 120); // should be random
String temp = Character.toString(input.charAt(i));
buttons[i].setText(temp);
buttons[i].setOnClickListener(this);
buttons[i].setId(i);
test1.setText(Integer.toString(buttons[i].getId()));
ll.addView(buttons[i],lp);
}
The position of these buttons should be completely random within the layout which can be easily achieved by generating random values for x and y coordinates. But I need the buttons not to overlap other buttons. Also due to 100x100dp dimension, sometimes the previously generated buttons are being partially overlapped by new ones.
You can actually figure this out programatically. Keep the co-ordinates of the views that you generate stored in a list. Then simply compare the co-ordinates to see if the new view intersects. You can use the following for a visualisation:
http://silentmatt.com/rectangle-intersection/
I hope you try writing code than copying it from someplace. :)
A SO link to help you out: Determine if two rectangles overlap each other?

Categories

Resources