Merge branch 'feature/animation' into 'master'

Feature/animation



See merge request !42
This commit is contained in:
pengfeizhou 2019-12-03 11:41:22 +08:00
commit eaca061573
13 changed files with 132 additions and 143 deletions

View File

@ -21,7 +21,7 @@ public class DoricRefreshView extends FrameLayout implements PullingListener {
private View content; private View content;
private Animation.AnimationListener mListener; private Animation.AnimationListener mListener;
private PullingListener mPullingListenr; private PullingListener mPullingListener;
public DoricRefreshView(@NonNull Context context) { public DoricRefreshView(@NonNull Context context) {
super(context); super(context);
@ -38,12 +38,15 @@ public class DoricRefreshView extends FrameLayout implements PullingListener {
public void setContent(View v) { public void setContent(View v) {
removeAllViews(); removeAllViews();
content = v; content = v;
if (v.getLayoutParams() instanceof FrameLayout.LayoutParams) { ViewGroup.LayoutParams params = v.getLayoutParams();
((LayoutParams) v.getLayoutParams()).gravity = Gravity.BOTTOM; if (params instanceof LayoutParams) {
((LayoutParams) params).gravity = Gravity.BOTTOM;
} else { } else {
LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); LayoutParams layoutParams = new LayoutParams(
params.gravity = Gravity.CENTER; params == null ? ViewGroup.LayoutParams.WRAP_CONTENT : params.width,
v.setLayoutParams(params); params == null ? ViewGroup.LayoutParams.WRAP_CONTENT : params.height);
layoutParams.gravity = Gravity.CENTER;
v.setLayoutParams(layoutParams);
} }
addView(v); addView(v);
} }
@ -53,28 +56,28 @@ public class DoricRefreshView extends FrameLayout implements PullingListener {
} }
public void setPullingListenr(PullingListener listenr) { public void setPullingListener(PullingListener listener) {
this.mPullingListenr = listenr; this.mPullingListener = listener;
} }
@Override @Override
public void startAnimation() { public void startAnimation() {
if (mPullingListenr != null) { if (mPullingListener != null) {
mPullingListenr.startAnimation(); mPullingListener.startAnimation();
} }
} }
@Override @Override
public void stopAnimation() { public void stopAnimation() {
if (mPullingListenr != null) { if (mPullingListener != null) {
mPullingListenr.stopAnimation(); mPullingListener.stopAnimation();
} }
} }
@Override @Override
public void setProgressRotation(float rotation) { public void setPullingDistance(float distance) {
if (mPullingListenr != null) { if (mPullingListener != null) {
mPullingListenr.setProgressRotation(rotation); mPullingListener.setPullingDistance(distance);
} }
} }

View File

@ -30,6 +30,8 @@ import androidx.swiperefreshlayout.widget.CircularProgressDrawable;
import android.view.animation.Animation.AnimationListener; import android.view.animation.Animation.AnimationListener;
import pub.doric.utils.DoricUtils;
/** /**
* @Description: pub.doric.pullable * @Description: pub.doric.pullable
* @Author: pengfei.zhou * @Author: pengfei.zhou
@ -117,11 +119,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
int mCustomSlingshotDistance; int mCustomSlingshotDistance;
private Animation mScaleAnimation;
private Animation mScaleDownAnimation;
private Animation mScaleDownToStartAnimation;
boolean mNotify; boolean mNotify;
@ -131,6 +128,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
private OnChildScrollUpCallback mChildScrollUpCallback; private OnChildScrollUpCallback mChildScrollUpCallback;
private DoricRefreshView mRefreshView; private DoricRefreshView mRefreshView;
private AnimationListener mRefreshListener = new AnimationListener() { private AnimationListener mRefreshListener = new AnimationListener() {
@Override @Override
public void onAnimationStart(Animation animation) { public void onAnimationStart(Animation animation) {
@ -158,6 +156,20 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
private int mPullDownHeight = 0; private int mPullDownHeight = 0;
private ValueAnimator headerViewAnimator; private ValueAnimator headerViewAnimator;
private void onRefreshAnimationEnd() {
if (mRefreshing) {
mRefreshView.startAnimation();
if (mNotify) {
if (mListener != null) {
mListener.onRefresh();
}
}
mCurrentTargetOffsetTop = mRefreshView.getTop();
} else {
reset();
}
}
void reset() { void reset() {
mRefreshing = false; mRefreshing = false;
if (headerViewAnimator != null && headerViewAnimator.isRunning()) { if (headerViewAnimator != null && headerViewAnimator.isRunning()) {
@ -169,6 +181,9 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
public void onAnimationUpdate(ValueAnimator animation) { public void onAnimationUpdate(ValueAnimator animation) {
mCurrentTargetOffsetTop = (int) animation.getAnimatedValue() mCurrentTargetOffsetTop = (int) animation.getAnimatedValue()
- mRefreshView.getMeasuredHeight(); - mRefreshView.getMeasuredHeight();
if (mRefreshView.getMeasuredHeight() > 0) {
mRefreshView.setPullingDistance(DoricUtils.px2dp(mRefreshView.getBottom()));
}
mRefreshView.requestLayout(); mRefreshView.requestLayout();
} }
}); });
@ -320,36 +335,13 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
} }
setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop); setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop);
mNotify = false; mNotify = false;
startScaleUpAnimation(mRefreshListener); mRefreshView.setVisibility(View.VISIBLE);
onRefreshAnimationEnd();
} else { } else {
setRefreshing(refreshing, false /* notify */); setRefreshing(refreshing, false /* notify */);
} }
} }
private void startScaleUpAnimation(AnimationListener listener) {
mRefreshView.setVisibility(View.VISIBLE);
mScaleAnimation = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
setAnimationProgress(interpolatedTime);
}
};
mScaleAnimation.setDuration(mMediumAnimationDuration);
if (listener != null) {
mRefreshView.setAnimationListener(listener);
}
mRefreshView.clearAnimation();
mRefreshView.startAnimation(mScaleAnimation);
}
/**
* Pre API 11, this does an alpha animation.
*
* @param progress
*/
void setAnimationProgress(float progress) {
}
private void setRefreshing(boolean refreshing, final boolean notify) { private void setRefreshing(boolean refreshing, final boolean notify) {
if (mRefreshing != refreshing) { if (mRefreshing != refreshing) {
@ -359,24 +351,11 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
if (mRefreshing) { if (mRefreshing) {
animateOffsetToCorrectPosition(mCurrentTargetOffsetTop, mRefreshListener); animateOffsetToCorrectPosition(mCurrentTargetOffsetTop, mRefreshListener);
} else { } else {
startScaleDownAnimation(mRefreshListener); onRefreshAnimationEnd();
} }
} }
} }
void startScaleDownAnimation(Animation.AnimationListener listener) {
mScaleDownAnimation = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
setAnimationProgress(1 - interpolatedTime);
}
};
mScaleDownAnimation.setDuration(SCALE_DOWN_DURATION);
mRefreshView.setAnimationListener(listener);
mRefreshView.clearAnimation();
mRefreshView.startAnimation(mScaleDownAnimation);
}
/** /**
* @return Whether the SwipeRefreshWidget is actively showing refresh * @return Whether the SwipeRefreshWidget is actively showing refresh
* progress. * progress.
@ -744,24 +723,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
} else { } else {
// cancel refresh // cancel refresh
mRefreshing = false; mRefreshing = false;
Animation.AnimationListener listener = null; animateOffsetToStartPosition(mCurrentTargetOffsetTop, null);
listener = new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
startScaleDownAnimation(null);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
};
animateOffsetToStartPosition(mCurrentTargetOffsetTop, listener);
} }
} }
@ -912,7 +874,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
ViewCompat.offsetTopAndBottom(mRefreshView, offset); ViewCompat.offsetTopAndBottom(mRefreshView, offset);
mCurrentTargetOffsetTop = mRefreshView.getTop(); mCurrentTargetOffsetTop = mRefreshView.getTop();
if (mRefreshView.getMeasuredHeight() > 0) { if (mRefreshView.getMeasuredHeight() > 0) {
mRefreshView.setProgressRotation((float) mRefreshView.getBottom() / (float) mRefreshView.getMeasuredHeight() * 2); mRefreshView.setPullingDistance(DoricUtils.px2dp(mRefreshView.getBottom()));
} }
} }

View File

@ -16,5 +16,5 @@ public interface PullingListener {
* *
* @param rotation Rotation is from [0..2] * @param rotation Rotation is from [0..2]
*/ */
void setProgressRotation(float rotation); void setPullingDistance(float rotation);
} }

View File

@ -33,7 +33,7 @@ public class RefreshableNode extends SuperNode<DoricSwipeLayout> implements Pull
@Override @Override
protected DoricSwipeLayout build() { protected DoricSwipeLayout build() {
DoricSwipeLayout doricSwipeLayout = new DoricSwipeLayout(getContext()); DoricSwipeLayout doricSwipeLayout = new DoricSwipeLayout(getContext());
doricSwipeLayout.getRefreshView().setPullingListenr(this); doricSwipeLayout.getRefreshView().setPullingListener(this);
return doricSwipeLayout; return doricSwipeLayout;
} }
@ -188,9 +188,9 @@ public class RefreshableNode extends SuperNode<DoricSwipeLayout> implements Pull
} }
@Override @Override
public void setProgressRotation(float rotation) { public void setPullingDistance(float rotation) {
if (mHeaderNode != null) { if (mHeaderNode != null) {
mHeaderNode.callJSResponse("setProgressRotation", rotation); mHeaderNode.callJSResponse("setPullingDistance", rotation);
} }
} }
} }

View File

@ -17,4 +17,5 @@ export default [
'src/PopoverDemo', 'src/PopoverDemo',
'src/AnimatorDemo', 'src/AnimatorDemo',
'src/ComplicatedAnimations', 'src/ComplicatedAnimations',
'src/ComplicatedDemo',
] ]

View File

@ -17,11 +17,12 @@ function thisLabel(str: string) {
class AnimationDemo extends Panel { class AnimationDemo extends Panel {
build(rootView: Group): void { build(rootView: Group): void {
const view = box(2) const view = box(2)
const view2 = box(3)
view.onClick = () => { view.onClick = () => {
modal(context).toast('Clicked') modal(context).toast('Clicked')
} }
vlayout([ vlayout([
title("Complicated Animation"), title("Complicated Animation"),
vlayout( vlayout(
[ [
hlayout([ hlayout([
@ -177,7 +178,17 @@ class AnimationDemo extends Panel {
] ]
).apply({ space: 10 } as IVLayout), ).apply({ space: 10 } as IVLayout),
stack([ stack([
view, view.also(v => {
v.x = 20
v.y = 0
v.width = 30
v.left = 15
}),
view2.also(v => {
v.x = v.y = 20
v.y = 40
v.scaleX = 1.5
})
]).apply({ ]).apply({
layoutConfig: layoutConfig().atmost(), layoutConfig: layoutConfig().atmost(),
backgroundColor: colors[1].alpha(0.3 * 255), backgroundColor: colors[1].alpha(0.3 * 255),

View File

@ -0,0 +1,49 @@
import { Panel, Group, vlayout, image, layoutConfig, ScaleType, refreshable, Color, pullable, stack, Image, Refreshable, TranslationAnimation, loge, log } from "doric";
import { title, icon_refresh } from "./utils";
@Entry
class MyDemo extends Panel {
build(root: Group) {
let refreshed: Refreshable
let headerImage: Image
stack([
refreshed = refreshable({
onRefresh: () => {
refreshed.setRefreshing(context, false)
},
header: pullable(context,
stack([]).apply({
backgroundColor: Color.RED,
layoutConfig: layoutConfig().exactly(),
width: 100,
height: 30,
}),
{
startAnimation: () => {
},
stopAnimation: () => {
},
setPullingDistance: (distance: number) => {
headerImage.scaleX = headerImage.scaleY = (headerImage.height + distance * 2) / headerImage.height
log(`Header Image scaleY:${headerImage.scaleY},height:${headerImage.height},distance:${distance}`)
},
}),
content: vlayout([]).apply({
backgroundColor: Color.YELLOW,
}),
}).apply({
layoutConfig: layoutConfig().atmost(),
}).also(v => {
v.top = 200
}),
headerImage = image({
imageUrl: "https://img.zcool.cn/community/01e75b5da933daa801209e1ffa4649.jpg@1280w_1l_2o_100sh.jpg",
layoutConfig: layoutConfig().exactly(),
width: root.width,
height: 200,
scaleType: ScaleType.ScaleAspectFill,
}),
]).in(root)
}
}

View File

@ -31,8 +31,8 @@ class RefreshableDemo extends Panel {
stopAnimation: () => { stopAnimation: () => {
log('stopAnimation') log('stopAnimation')
}, },
setProgressRotation: (rotation: number) => { setPullingDistance: (distance: number) => {
refreshImage.rotation = rotation refreshImage.rotation = distance / 30
}, },
}), }),
content: (vlayout([ content: (vlayout([
@ -83,18 +83,6 @@ class RefreshableDemo extends Panel {
refreshView.setRefreshable(context, false) refreshView.setRefreshable(context, false)
} }
} as IText), } as IText),
label('Rotate self').apply({
width: 300,
height: 50,
backgroundColor: colors[0],
textSize: 30,
textColor: Color.WHITE,
layoutConfig: layoutConfig().exactly(),
} as IText).also(v => {
v.onClick = () => {
v.nativeChannel(context, "setRotation")(0.25)
}
}),
]).apply({ ]).apply({
layoutConfig: layoutConfig().atmost().h(LayoutSpec.WRAP_CONTENT), layoutConfig: layoutConfig().atmost().h(LayoutSpec.WRAP_CONTENT),
gravity: gravity().centerX(), gravity: gravity().centerX(),

View File

@ -65,8 +65,8 @@ export function rotatedArrow(context: BridgeContext) {
stopAnimation: () => { stopAnimation: () => {
log('stopAnimation') log('stopAnimation')
}, },
setProgressRotation: (rotation: number) => { setPullingDistance: (distance: number) => {
refreshImage.rotation = rotation refreshImage.rotation = distance / 30
}, },
}) })
} }

View File

@ -152,13 +152,13 @@ - (void)stopAnimation {
[self.headerNode callJSResponse:@"stopAnimation", nil]; [self.headerNode callJSResponse:@"stopAnimation", nil];
} }
- (void)setProgressRotation:(CGFloat)rotation { - (void)setPullingDistance:(CGFloat)distance {
[self.headerNode callJSResponse:@"setProgressRotation", @(rotation), nil]; [self.headerNode callJSResponse:@"setPullingDistance", @(distance), nil];
} }
- (void)setRefreshing:(NSNumber *)refreshable withPromise:(DoricPromise *)promise { - (void)setRefreshing:(NSNumber *)refreshable withPromise:(DoricPromise *)promise {
self.view.refreshing = [refreshable boolValue]; self.view.refreshing = [refreshable boolValue];
[promise resolve:nil]; [promise resolve:nil];
} }
- (void)setRefreshable:(NSNumber *)refreshing withPromise:(DoricPromise *)promise { - (void)setRefreshable:(NSNumber *)refreshing withPromise:(DoricPromise *)promise {

View File

@ -1,18 +1,3 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// //
// Created by pengfei.zhou on 2019/11/26. // Created by pengfei.zhou on 2019/11/26.
// //
@ -24,7 +9,7 @@
- (void)stopAnimation; - (void)stopAnimation;
- (void)setProgressRotation:(CGFloat)rotation; - (void)setPullingDistance:(CGFloat)rotation;
@end @end
@interface DoricSwipeRefreshLayout : UIScrollView @interface DoricSwipeRefreshLayout : UIScrollView

View File

@ -68,7 +68,14 @@ - (BOOL)requestFromSubview:(UIView *)subview {
return [super requestFromSubview:subview]; return [super requestFromSubview:subview];
} }
- (void)layoutSubviews {
[super layoutSubviews];
}
- (void)layoutSelf:(CGSize)targetSize { - (void)layoutSelf:(CGSize)targetSize {
if (self.contentOffset.y != 0) {
return;
}
self.width = targetSize.width; self.width = targetSize.width;
self.height = targetSize.height; self.height = targetSize.height;
[self.headerView also:^(UIView *it) { [self.headerView also:^(UIView *it) {
@ -109,7 +116,7 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y <= 0) { if (scrollView.contentOffset.y <= 0) {
[self.swipePullingDelegate setProgressRotation:-scrollView.contentOffset.y / self.headerView.height * 2]; [self.swipePullingDelegate setPullingDistance:-scrollView.contentOffset.y];
} }
} }
@ -122,31 +129,14 @@ - (void)setRefreshing:(BOOL)refreshing {
return; return;
} }
if (refreshing) { if (refreshing) {
[self setContentOffset:CGPointMake(0, -self.headerView.height) animated:YES];
self.scrollEnabled = NO;
if (self.onRefreshBlock) { if (self.onRefreshBlock) {
self.onRefreshBlock(); self.onRefreshBlock();
} }
[UIView animateWithDuration:.3f
animations:^{
self.contentOffset = (CGPoint) {0, -self.headerView.height};
self.contentInset = UIEdgeInsetsMake(self.headerView.height, 0, 0, 0);
}
completion:^(BOOL finished) {
[self.swipePullingDelegate startAnimation];
self.scrollEnabled = NO;
}
];
} else { } else {
self.bounces = YES; [self setContentOffset:(CGPoint) {0, 0} animated:YES];
[UIView animateWithDuration:.3f self.scrollEnabled = YES;
animations:^{
self.contentOffset = (CGPoint) {0, 0};
self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}
completion:^(BOOL finished) {
[self.swipePullingDelegate stopAnimation];
self.scrollEnabled = YES;
}
];
} }
_refreshing = refreshing; _refreshing = refreshing;
} }

View File

@ -62,13 +62,13 @@ export function refreshable(config: IRefreshable) {
export interface IPullable { export interface IPullable {
startAnimation(): void startAnimation(): void
stopAnimation(): void stopAnimation(): void
setProgressRotation(rotation: number): void setPullingDistance(distance: number): void
} }
export function pullable(context: BridgeContext, v: View, config: IPullable) { export function pullable(context: BridgeContext, v: View, config: IPullable) {
Reflect.set(v, 'startAnimation', config.startAnimation) Reflect.set(v, 'startAnimation', config.startAnimation)
Reflect.set(v, 'stopAnimation', config.stopAnimation) Reflect.set(v, 'stopAnimation', config.stopAnimation)
Reflect.set(v, 'setProgressRotation', config.setProgressRotation) Reflect.set(v, 'setPullingDistance', config.setPullingDistance)
return v return v
} }