I'm trying to scroll a webview programaticly but I'm having some problems. webView.setScrollY() doesn't give me an animation an webView.flingScroll() seems to behave diffrently depending on how long the page is. What is the best way to do this?
You can scroll using ObjectAnimator by providing current position of webview like this API 11+
ObjectAnimator anim = ObjectAnimator.ofInt(webView, "scrollY", webView.getScrollPositionY(), 0);
anim.setDuration(500).start();
You can use webView.scrollTo(x, y) method. However, this will scroll instantly.
There is no method available for WebView to scroll with animation. If you really have to do it, put the WebView into ScrollView and then you can use e.g. smoothScrollBy etc.
private final Property<WebView, Integer> WEBVIEW_SCROLL = new Property<WebView, Integer>(Integer.class, "") {
#Override
public Integer get(WebView object) {
return object.getScrollY();
}
#Override
public void set(WebView object, Integer value) {
object.scrollTo(object.getScrollX(), value);
}
};
ObjectAnimator.ofInt(mWebView, WEBVIEW_SCROLL, targetY).setDuration(duration).start();
It's work for me~,you can try this~
Related
I was trying to find documentation about how to create icon animation of FAB's (of the Design support library), after searching a while i couldn't find any information about it and the AnimationDrawable reference in android developers doesn't work for FAB's even if the class is a child of ImageView.
but manage to get a workaround that works just fine.
The technic I used is similar to the one exposed on the DrawableAnimation documentation, and using the Property Animation API doc.
First I use the ValueAnimator class, and an int array containing the ids of the drawables that you're going to use in your animation.
final int[] ids = {R.drawable.main_button_1,R.drawable.main_button_2,R.drawable.main_button_3,R.drawable.main_button_4,R.drawable.main_button_5,R.drawable.main_button_6, R.drawable.main_button_7};
fab = (FloatingActionButton) findViewById(R.id.yourFabID);
valueAnimator = ValueAnimator.ofInt(0, ids.length - 1).setDuration(yourAnimationTime);
valueAnimator.setInterpolator( new LinearInterpolator() /*your TimeInterpolator*/ );
Then set up an AnimationUpdateListener, and define the change in icon behavior with the method FloatinActionButton.setImageDrawable(Drawable yourDrawable).
But the ValueAnimator updates by default every available frame (depending on the load in hardware), but we don't need to redraw the icon if it has already been drawn, so that is why I use the variable "i"; so each icon is drawn only once. (the timing depends on the interpolator you define)
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int i = -1;
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
if(i!=animatedValue) {
fab.setImageDrawable(getResources().getDrawable(ids[animatedValue]));
i = animatedValue;
}
}
});
This implementation allows you to play the animation backward with the method ValueAnimator.reverse();
I know is not a pro solution but it's the only one I've figured out to work on all API's supporting the PropertyAnimation. Please, if you know a better solution post it here, if not I hope this post is helpful
You can achieve FAB's src drawable animation quite similarly to other views that use background for AnimationDrawable.
For general views' background drawable animation, see Use AnimationDrawable.
However, you cannot call getBackground() to get FAB's src.
Instead, use getDrawable().
Example:
FloatingActionButton loginButton = findViewById(R.id.loginButton);
loginAnimation = (AnimationDrawable) loginButton.getDrawable();
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
loginAnimation.start();
}
});
I basically have to smooth scroll a listview and update a row at the same time.
I do it with a simple approach for now:
mListViewWeeks.post(new Runnable() {
#Override
public void run() {
// update the row concerned
updateItemAtPosition(rowIndex);
int duration = 200;
mListView.smoothScrollToPositionFromTop(rowIndex, 0, duration);
}
});
with the updateItemAtPosition() function:
private void updateItemAtPosition(int position) {
int visiblePosition = mListView.getFirstVisiblePosition();
View view = mListView.getChildAt(position - visiblePosition);
mListView.getAdapter().getView(position, view, mListView);
}
It's working well at a reasonable scroll speed, but when going faster (calling the first block above at a high rate) it can get a bit laggy. Is there anything that I can do to improve updating a row while scrolling smoothly?
You should'nt acces the iew dirrectly like this. Instead you should update your model object displayed by the list and call notifyDataSetChanged() in your adapter.
Well, I'm really late in the game. It looks like one of the reason why RecyclerView was introduced. I'm gonna try to use this component from now on.
A combination of layoutManager.scrollToPosition(position);
and adapter.notifyItemChanged(position); does the job. Everything runs smoothly!!
I'm using
<ExpandableListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ExpandableListView>
i want add animation slide for child when onclick parent . So How can i do ?
Final Update
It's been quite a while since I wrote this answer. Since then a lot has changed. The biggest change is with the introduction of RecyclerView that makes animating a list or grid easy. I highly recommend switching over to RecyclerViews if you can. For those who can't I will see what I can do regarding fixing the bugs for my library.
Original answer
I actually do not like the popular implementation of an animated ExpandableListView that simply uses a ListView with an expand animation because in my use case, each of my groups had a lot of children, therefore it was not feasible to use a normal ListView as the child views will not be recycled and the memory usage will be huge with poor performance. Instead, I went with a much more difficult but more scalable and flexible approach.
I extended the ExpandableListView class and overrode the onCollapse and onExpand functions, I also created a subclass of a BaseExpandableListAdapter called AnimatedExpandableListAdapter. Inside the adapter, I overrode the getChildView function and made the function final so that the function cannot be overrode again. Instead I provided another function called getRealChildView for subclasses to override to provide a real child view. I then added an animation flag to the class and made getChildView return a dummy view if the animation flag was set and the real view if the flag was not set. Now with the stage set I do the following for onExpand:
Set the animation flag in the adapter and tell the adapter which group is expanding.
Call notifyDataSetChanged() (forces the adapter to call getChildView() for all views on screen).
The adapter (in animation mode) will then create a dummy view for the expanding group that has initial height 0. The adapter will then get the real child views and pass these views to the dummy view.
The dummy view will then start to draw the real child views within it's own onDraw() function.
The adapter will kick off an animation loop that will expand the dummy view until it is of the right size. It will also set an animation listener so that it can clear the animation flag once the animation completes and will call notifyDataSetChanged() as well.
Finally with all of this done, I was able to not only get the desired animation effect but also the desired performance as this method will work with group with over 100 children.
For the collapsing animation, a little more work needs to be done to get this all setup and running. In particular, when you override onCollapse, you do not want to call the parent's function as it will collapse the group immediately leaving you no chance to play an animation. Instead you want to call super.onCollapse at the end of the collapse animation.
UPDATE:
I spent some time this weekend to rewrite my implementation of this AnimatedExpandableListView and I'm releasing the source with an example usage here:
https://github.com/idunnololz/AnimatedExpandableListView/
animateLayoutChanges adds auto-animation
<ExpandableListView
android:animateLayoutChanges="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
#idunnololz solution works great. however i would like to add some code to collapse previously expanded group.
private int previousGroup=-1;
listView.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
// We call collapseGroupWithAnimation(int) and
// expandGroupWithAnimation(int) to animate group
// expansion/collapse.
if (listView.isGroupExpanded(groupPosition)) {
listView.collapseGroupWithAnimation(groupPosition);
previousGroup=-1;
} else {
listView.expandGroupWithAnimation(groupPosition);
if(previousGroup!=-1){
listView.collapseGroupWithAnimation(previousGroup);
}
previousGroup=groupPosition;
}
return true;
}
});
#idunnololz solution is working great, but I experienced weird behavior with my custom layout for group. The expand operation was not executed properly, the collapse however worked perfect. I imported his test project and it worked just fine, so I realized the problem is with my custom layout. However when I was not able to locate the problem after some investigation, I decided to uncomment these lines of code in his AnimatedExpandListView:
if (lastGroup && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return expandGroup(groupPos, true);
}
which caused the problem (my app is aimed for Android 4.0+).
Found this snnipet not remebering where here in Stack Overflow. Have two basic static methods: expand(View v) and collapse(View v).
You only have to pass the view you want to hide show.
Note: I Don't recomend pass a view having wrap_content as height. May not work fine.
public class expand {
public static void expand(View view) {
view.setVisibility(View.VISIBLE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(widthSpec, heightSpec);
ValueAnimator mAnimator = slideAnimator(view, 0, view.getMeasuredHeight());
mAnimator.start();
}
public static void collapse(final View view) {
int finalHeight = view.getHeight();
ValueAnimator mAnimator = slideAnimator(view, finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
view.setVisibility(View.GONE);
}
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
mAnimator.start();
}
private static ValueAnimator slideAnimator(final View v, int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.height = value;
v.setLayoutParams(layoutParams);
}
});
return animator;
}
}
I have a Gallery widget set up to auto advance every 10000ms. However the transition between views is instantaneous and I would prefer to have a transition.
My advancing method is like so:
private void tickerAdvance() {
int selectedItemPosition = mTickerGallery.getSelectedItemPosition();
if (selectedItemPosition + 1 == mTickerGallery.getCount()) {
mTickerGallery.setSelection(0, true);
} else {
mTickerGallery.setSelection(selectedItemPosition + 1, true);
}
}
I was under the impression that setting the animation to true would cause it to animate between states. In my XML I've also added animationDuration="500", however the transition still pops between states instantly.
The problem is because you have used the setSelection() which obviously won't give you the feel of an Gallery being scrolled. SO instead of using setSelection() you have to override the onScroll() of gallery.
Here is how you do it.
Assuming that you have made the necessary steps for auto advancing periodically, now do this code.
MotionEvent e1, e2;
gallery.onScroll(e1, e2, scroll_limit , 0); //scroll limit is your integer variable for scroll limit.
The answer I came up with is that the Gallery API is terribly non-extensible. There are multiple package private or private methods that would unlock this functionality without a kludge including moveNext, FlingRunnable.startwithdistance, and scrollToChild. Alas, they are all unavailable.
Instead the best answer I was able to come up with was to override setSelection to get all the behaviors I needed. In the setSelection method I reverse the deceleration algorithm to calculate a velocity for a calculated distance and then call onFling. This is a nasty kludge could be made a ton better by making any of the above methods protected or public (I can't fathom a reason why at least moveNext and scrollToChild shouldn't be).
i had a similar task to make item to item animation and i decided to choose gallery, so i tried a lot of things, but the best way is to subclass gallery and add this:
boolean avoidSound = false;
public void showNext() {
avoidSound = true;
this.onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, null);
}
public void playSoundEffect(int soundConstant) {
if (avoidSound) {
avoidSound = false;
} else {
super.playSoundEffect(soundConstant);
}
}
just call showNext() and it will do an animation
Would it be possible to hide a view off the top edge of the screen, and only have it appear if the user scrolls upwards?
My first attempt used a scrollview, but it seems that scrollTo() doesn't work unless I used postDelayed (it doesn't even work with Post()). I tried adding it to the scrollview's view tree observer onPreDraw() event and it still doesn't work unless I delay it, so there is an ugly glitch when the activity is first launched.
The second issue is that if the onscreen keyboard is minimized, the view no longer needs to scroll so hiding things by using a scroll offset no longer works. I thought about manipulating the height in code, but this seems pretty hackish.
Is there a better way to do this than by using a scrollview? Alternatively, Does anyone have any tips on the best place to place the scrollTo (the end of onCreate does not work nor the other places I have tried) so I don't need to use postDelayed? That would at least eliminate one glitch.
Thanks!
This is the code I'm using right now, which is the least glitchy but I don't understand why it doesn't work until the third time onPreDraw() is called.
mScrollView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
{
#Override
public boolean onPreDraw()
{
final int fieldYStart = mFieldIWantAtTheTop.getTop();
if (mFieldIWantAtTheTopYStart != fieldYStart
|| mScrollView.getScrollY() < 10)
{
mFieldIWantAtTheTopYStart = fieldYStart;
mScrollView.post(new Runnable()
{
#Override
public void run()
{
Log.v("Testing", "scrolling!");
mScrollView.scrollTo(0, mFieldIWantAtTheTopYStart);
Log.v("Testing", "scroll is now=" + mScrollView.getScrollY());
}
});
}
return true;
}
});
I also tried using a custom scrollview as mentioned below, but this does not solve the issue of the graphical glitch:
#Override
public void onMeasure(int measureWidthSpec, int measureHeightSpec) {
super.onMeasure(measureWidthSpec, measureHeightSpec);
Log.v("Testing", "Scrolling");
post(
new Runnable()
{
public void run()
{
scrollTo(0, 100);
Log.v("Testing", "ScrollY = " + getScrollY());
}
});
}
This code works as does the onPreDraw() code above but there is still a glitch when the activity is launched because the activity is first drawn with the scroll at 0.
I haven't tried this, but you may want to create a custom ScrollView and override onMeasure:
ScrollView scroll = new ScrollView(this) {
#Override
public void onMeasure(int measureWidthSpec, int measureHeightSpec) {
super.onMeasure(measureWidthSpec, measureHeightSpec);
scrollTo(...);
}
};
It seems like this would be the earliest point that scrollTo would be valid.
Edit - I found this answer, which apparently worked for the asker. Is this the method you tried?