I have a star animation for giving rating and I created three of such LottieAnimationViews inside my fragment for the purpose of reuse-ability. The LottieAnimation doesn't even start when I run it from inside the onCreate() method of my Fragment (I am using support Fragments). The exact same code runs the animation if it is inside an Activity instead of a fragment. Here's my code...
mLottieStarView1 = findViewById(R.id.rating_lottie_star_1); //LottieView
starLayout1 = findViewById(R.id.rating_star_layout_1); //Enclosing LinearLayout
mValueAnimator1 = ValueAnimator.ofFloat(0f, 1f).setDuration(1500);
//Create animation update methods
mValueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { //Star 1
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mLottieStarView1.setProgress((Float) valueAnimator.getAnimatedValue());
}
});
//Set listener on enclosing layout to run animation on touch
starLayout1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mLottieStarView2.setProgress(0f);
mLottieStarView3.setProgress(0f);
mValueAnimator1.start();
}
});
Make sure you set the image View to isClickable = true
and isFocusable = true in xml.
Start the lottie animation using the lottieView.playAnimation(); method and for the unclick try this
if(lottieTest.getFrame() == lottieTest.getMaxFrame()) {
lottieTest.setFrame(1);
}
Related
I have a Recyclerview, im animating a view inside individual list item, but when I scroll the recyclerview the animation is stopping. Its because recyclerview removes the items form its view so when we scroll back it fetches it back! But now i want that animation to keep going as I would stop it only when i get data from server!
All I want is the animation that I start in the individual items inside the recylerview shouldn't stop even if the recyclerview is scrolled and the view is out of focus and comes back to focus! I need to stop the animation in the code when I get the server data! I have the code where to stop the animation and it works if the item is not scrolled off the view!
btn.onClick -- this button is the onClick for the recyclerview list
item 1 btn.startAnimation(anim.xml) -- starting the animation
onSuccess -- server returns success btn.clearAnimation();
but before the onSuccess if we scroll the list the animation is stopped!
Please help!
By inspiring from crymson's answer i have made little easy and useful solution using tag method of View instead setting a boolean in complicated logic of your custom adapter.
#Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
if (holder.getItemViewType() == TYPE_AD)
((ViewHolderForAd) holder).ivStory.setTag(false);
}
public class ViewHolderForAd extends RecyclerView.ViewHolder {
private ImageView ivStory;
TextView tvName;
public ViewHolderForAd(View view) {
super(view);
ivStory = (ImageView) view.findViewById(R.id.ivStoryImage);
tvName = (TextView) view.findViewById(R.id.tvAppName);
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int pos = getAdapterPosition();
if (pos < 0) {
pos = (int) v.getTag();
}
customItemClickListener.onItemClicked(v, pos);
}
});
//ivStory.startAnimation(AnimationUtils.loadAnimation(context, R.anim.pulse_story));
ivStory.setTag(false); //Set default tag false to decrease risk of null
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
//...Your code...
if (!(boolean) holder1.ivStory.getTag()) {
holder1.ivStory.setTag(true);
holder1.ivStory.startAnimation(AnimationUtils.loadAnimation(context, R.anim.pulse_story));
}
//...Your code...//
}
You can use setTag(key, object) instead of setTag(object) if you already tagged something(like position) in your imageView.
Hope this helps someone.
Hard to give you a full solution but have you tried saving the animation state inside the ViewHolder that you are using? I'd recommend saving a boolean flag in the ViewHolder class you defined like isAnimating which is initially set to false and in your onBindViewHolder(...) method you can do something like
if (viewHolder.isAnimating) {
// start animation
} else {
// clear animation
}
viewHolder.btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.isAnimating = true;
// start animation
}
});
I'm trying to change the style attribute "colorControlNormal" of my app programmatically and during runtime, but I didn't have any results.
This property is the color that will tint the hamburger & back icons of the new Toolbar viewGroup. Beside, I'm using the v7 compatibility library.
I heard that we cannot change app theme during runtime, but I'm looking for an answer, even if it's not so clean way.
Edit:
I just figured that gmail is doing what i want, when you click on the search icon, the white hamburger icon turn into grey back.
Waiting for more.
I spent one day, played with different implementation. So my opinion, the best way todo that it copy paste DrawerArrowDrawable from AppCompat v7 library.
https://gist.github.com/IstiN/5d542355935fd7f0f357 - take a look on the code with some optimization
than you can use it in your main activity with code below
DrawerArrowDrawable drawable = new DrawerArrowDrawable(this, this);
ImageView menuButton = (ImageView) findViewById(R.id.arrow);
menuButton.setImageDrawable(drawable);
menuButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((DrawerLayout)findViewById(R.id.drawer)).openDrawer(Gravity.START);
}
});
when you start new fragment, you need to create one more view on the same place and add second code to your fragment
private DrawerArrowDrawable mArrowDrawable;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mArrowDrawable = new DrawerArrowDrawable(getActivity(), getActivity());
ImageView topButton = (ImageView) view.findViewById(R.id.arrow);
topButton.setImageDrawable(mArrowDrawable);
topButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
closeSearch();
}
});
//run animation from hamburger to arrow
animate(0, 1, null);
....
private void animate(int startValue, int endvalue, Animator.AnimatorListener listener) {
ValueAnimator anim = ValueAnimator.ofFloat(startValue, endvalue);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float slideOffset = (Float) valueAnimator.getAnimatedValue();
mArrowDrawable.setProgress(slideOffset);
}
});
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(300);
if (listener != null) {
anim.addListener(listener);
}
anim.start();
}
to make animation from arrow to hamburger handle back button and execute code
animate(1, 0, null);
you also need to wait in your fragment while animation will not finish, but it another questions.
If you have any questions ask in comments.
I am a new in android programming, I made a layout with this figure:
Now I want to know when one of these buttons clicked I should run an new activity or change visibility to false and show new layout without run a new activity, what is the best solution?
You consider that count of these buttons are more than ten.
I want show a text with image,..(when clicked) because that is a educational book and these buttons are chapters list of that book
for an example if you want to change only the layout then you could do something like this
FirstButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
FirstView();
}
});
/
void FirstView(){
setContentView(R.layout.yourOtherLayout);
// then declare the layout views here.
firstView=false;
}
you can do this in all the buttons just create different methods for each
to handle the Back Button you can declare Boolean variables and use If else Statement to loop through them for example
boolean firstView = true, secondView = true;
#Override
public void onBackPressed(){
if (firstView == false ){
then firstView Is Showing.
// show the view you want and set
firstView = true;
}else if (SO ON)...
else { super.OnBackPressed(); // exit }
}
This is a code for blinking textview on a button click..
start.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
recordShow.setVisibility(View.VISIBLE);
Animation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(1000); //You can manage the time of the blink with this parameter
anim.setStartOffset(20);
anim.setRepeatMode(Animation.REVERSE);
anim.setRepeatCount(Animation.INFINITE);
recordShow.startAnimation(anim);
}
i have to stop blinking on another button click...what to do..??
Another approach could be:
1. Declare the Animation and TextView objects globally (outside any methods) in your Activity.
private Animation mAnim;
private TextView mRecordShow;
2. Setup a class that sets your animation properties and starts it. Let this class expect a TextView widget as its parameter.
protected void setBlinkingText(TextView textView) {
mAnim = new AlphaAnimation(0.0f, 1.0f);
mAnim.setDuration(1000); // Time of the blink
mAnim.setStartOffset(20);
mAnim.setRepeatMode(Animation.REVERSE);
mAnim.setRepeatCount(Animation.INFINITE);
textView.startAnimation(mAnim);
}
3. Setup another class that stops your animation on a given text view. Let this class expect a TextView widget as its parameter as well.
protected void removeBlinkingText(TextView textView) {
textView.clearAnimation();
}
4. Now you can use your classes wherever desired, passing it the appropriate text views.
e.g.
(a) In your onClick() method where you want to start the animation, replace all your animation code with:
setBlinkingText(mRecordShow);
(b) wherever you want to stop the animation on that text view, just call:
removeBlinkingText(mRecordShow);
The following assumes you want to stop the blink by clicking the same button. If you want to stop the click using a different button, you can split the if-else in the onClick() below into separate click handlers.
First, move anim outside onClick() and make it a field of the containing class. You need anim to be stored somewhere so you can cancel it later.
Animation anim = new AlphaAnimation(0.0f, 1.0f)
anim.setDuration(1000); //You can manage the time of the blink with this parameter
anim.setStartOffset(20);
anim.setRepeatMode(Animation.REVERSE);
anim.setRepeatCount(Animation.INFINITE);
Second, create a boolean field in the containing class to keep track of whether the TextView is currently blinking:
boolean mBlinking = false;
Then:
#Override
public void onClick(View v)
{
recordShow.setVisibility(View.VISIBLE);
if(!mBlinking){
recordShow.startAnimation(anim);
mBlinking = true;
} else{
recordShow.clearAnimation(anim); // cancel blink animation
recordShow.setAlpha(1.0f); // restore original alpha
mBlinking = false;
}
}
I have an Activity containing a ViewPager that displays N fragments. Each fragment is showing the properties of an object from an ArrayList in my ViewPager's custom adapter (extends FragmentStatePagerAdapter).
The fragment has (among other things) a button that should remove the currently displayed fragment and scroll to the next one with setCurrentItem(position, true) so that if the user scrolls back, the previous item is gone. I do so by using something like this (simplified):
deleteButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
MyActivity parentActivity = (MyActivity)getActivity();
// First, scroll to next item (smoothly)
parentActivity.pager.setCurrentItem(parentActivity.pager.getCurrentItem()+1, true);
// Database stuff...
doSomeDBOperations();
// Method in Activity that removes the current object (I believe this method is working fine and yes, it calls notifyDataSetChanged())
parent.removeObject(currentObject);
}
});
This has the desired behavior as the object represented by the fragment whose delete button was pressed gets removed and the viewpager goes to the next page.
My problem is that the ViewPager doesn't scroll smoothly but rather "jumps instantly" to the next fragment. If I comment the removeObject() call, the smooth scroll works (but the item isn't removed). I believe it's has something to do with the removeObject() being called before the setCurrentItem() has finished the smooth scrolling animation?
Any ideas on how to fix this and achieve item removal + smooth scroll? If my assumption is correct, how can I make sure I get the smooth scroll to finish before removing the object?
EDIT 1:
My assumption seems correct. If I put the parent.removeObject(currentObject) inside
// ...inside the previously shown public void onClick(View v)...
confirm.postDelayed(new Runnable() {
#Override
public void run() {
// Method in Activity that removes the current object (I believe this method is working fine and yes, it calls notifyDataSetChanged())
parent.removeObject(currentObject);
}
}, 1000);
so that the removeObject() call waits for a second, it works as expected: scroll to the next item, remove the previous. But this is a very ugly workaround so I'd still like a better approach.
EDIT 2:
I figured out a possible solution (see below).
I ended up overriding the
public void onPageScrollStateChanged(int state)
method:
Whenever the user presses the delete button in the fragment, the listener sets a bool in the current item (flagging it for deletion) and scrolls to the next one.
When the onPageScrollStateChanged detects that the scroll state changed to ViewPager.SCROLL_STATE_IDLE (which happens when the smooth scroll ends) it checks if the previous item was marked for deletion and, if so, removes it from the ArrayList and calls notifyDataSetChanged().
By doing so, I've managed to get the ViewPager to smoothly scroll to the next position and delete the previous item when the "delete" button is pressed.
EDIT: Code snippet.
#Override
public void onPageScrollStateChanged(int state)
{
switch(state)
{
case ViewPager.SCROLL_STATE_DRAGGING:
break;
case ViewPager.SCROLL_STATE_IDLE:
int previousPosition = currentPosition - 1;
if(previousPosition < 0){
previousPosition = 0;
}
MyItem previousItem = itemList.get(previousPosition);
if(previousItem.isDeleted())
{
deleteItem(previousItem);
// deleteItem() Does some DB operations, then calls itemList.remove(position) and notifyDataSetChanged()
}
break;
case ViewPager.SCROLL_STATE_SETTLING:
break;
}
}
Have you tried ViewPager.OnPageChangeListener?
I would call removeObject(n) method in OnPageChangeListener.onPageSelected(n+1) method.
I did something different that works smoothly. The idea is to to remove the current item with animation (setting its alpha to 0), then translating horizontally the left or right item (with animation) to the now invisible item position.
After the animation is complete, I do the actual data removal and notfyDataSetChanged() call.
This remove() method I put inside a subclass of ViewPager
public void remove(int position, OnViewRemovedListener onViewRemovedListener) {
final int childCount = getChildCount();
if (childCount > 0) {
View toRemove = getChildAt(position);
int to = toRemove.getLeft();
final PagerAdapter adapter = getAdapter();
toRemove.animate()
.alpha(0)
.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime))
.setListener(new SimpleAnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
if (childCount == 1) {
if (onViewRemovedListener != null) onViewRemovedListener.onRemoved(position, -1);
if (adapter!= null) adapter.notifyDataSetChanged();
}
}
})
.start();
if (childCount > 1) {
int newPosition = position + 1 <= childCount - 1 ? position + 1 : position - 1;
View replacement = getChildAt(newPosition);
int from = replacement.getLeft();
replacement.animate()
.setInterpolator(new DecelerateInterpolator())
.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime))
.translationX(to - from)
.setListener(new SimpleAnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
if (onViewRemovedListener != null) onViewRemovedListener.onRemoved(position, newPosition);
if (adapter!= null) adapter.notifyDataSetChanged();
}
})
.start();
}
}
}
public interface OnViewRemovedListener {
void onRemoved(int position, int newPosition);
}