diff --git a/Android/doric/src/main/java/pub/doric/refresh/DoricRefreshView.java b/Android/doric/src/main/java/pub/doric/refresh/DoricRefreshView.java index 8b1ded39..43bd5b1a 100644 --- a/Android/doric/src/main/java/pub/doric/refresh/DoricRefreshView.java +++ b/Android/doric/src/main/java/pub/doric/refresh/DoricRefreshView.java @@ -21,7 +21,7 @@ public class DoricRefreshView extends FrameLayout implements PullingListener { private View content; private Animation.AnimationListener mListener; - private PullingListener mPullingListenr; + private PullingListener mPullingListener; public DoricRefreshView(@NonNull Context context) { super(context); @@ -38,12 +38,15 @@ public class DoricRefreshView extends FrameLayout implements PullingListener { public void setContent(View v) { removeAllViews(); content = v; - if (v.getLayoutParams() instanceof FrameLayout.LayoutParams) { - ((LayoutParams) v.getLayoutParams()).gravity = Gravity.BOTTOM; + ViewGroup.LayoutParams params = v.getLayoutParams(); + if (params instanceof LayoutParams) { + ((LayoutParams) params).gravity = Gravity.BOTTOM; } else { - LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - params.gravity = Gravity.CENTER; - v.setLayoutParams(params); + LayoutParams layoutParams = new LayoutParams( + params == null ? ViewGroup.LayoutParams.WRAP_CONTENT : params.width, + params == null ? ViewGroup.LayoutParams.WRAP_CONTENT : params.height); + layoutParams.gravity = Gravity.CENTER; + v.setLayoutParams(layoutParams); } addView(v); } @@ -53,28 +56,28 @@ public class DoricRefreshView extends FrameLayout implements PullingListener { } - public void setPullingListenr(PullingListener listenr) { - this.mPullingListenr = listenr; + public void setPullingListener(PullingListener listener) { + this.mPullingListener = listener; } @Override public void startAnimation() { - if (mPullingListenr != null) { - mPullingListenr.startAnimation(); + if (mPullingListener != null) { + mPullingListener.startAnimation(); } } @Override public void stopAnimation() { - if (mPullingListenr != null) { - mPullingListenr.stopAnimation(); + if (mPullingListener != null) { + mPullingListener.stopAnimation(); } } @Override - public void setProgressRotation(float rotation) { - if (mPullingListenr != null) { - mPullingListenr.setProgressRotation(rotation); + public void setPullingDistance(float distance) { + if (mPullingListener != null) { + mPullingListener.setPullingDistance(distance); } } diff --git a/Android/doric/src/main/java/pub/doric/refresh/DoricSwipeLayout.java b/Android/doric/src/main/java/pub/doric/refresh/DoricSwipeLayout.java index 03840f27..fca764d5 100644 --- a/Android/doric/src/main/java/pub/doric/refresh/DoricSwipeLayout.java +++ b/Android/doric/src/main/java/pub/doric/refresh/DoricSwipeLayout.java @@ -30,6 +30,8 @@ import androidx.swiperefreshlayout.widget.CircularProgressDrawable; import android.view.animation.Animation.AnimationListener; +import pub.doric.utils.DoricUtils; + /** * @Description: pub.doric.pullable * @Author: pengfei.zhou @@ -117,11 +119,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent int mCustomSlingshotDistance; - private Animation mScaleAnimation; - - private Animation mScaleDownAnimation; - - private Animation mScaleDownToStartAnimation; boolean mNotify; @@ -131,6 +128,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent private OnChildScrollUpCallback mChildScrollUpCallback; private DoricRefreshView mRefreshView; + private AnimationListener mRefreshListener = new AnimationListener() { @Override public void onAnimationStart(Animation animation) { @@ -158,6 +156,20 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent private int mPullDownHeight = 0; private ValueAnimator headerViewAnimator; + private void onRefreshAnimationEnd() { + if (mRefreshing) { + mRefreshView.startAnimation(); + if (mNotify) { + if (mListener != null) { + mListener.onRefresh(); + } + } + mCurrentTargetOffsetTop = mRefreshView.getTop(); + } else { + reset(); + } + } + void reset() { mRefreshing = false; if (headerViewAnimator != null && headerViewAnimator.isRunning()) { @@ -169,6 +181,9 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent public void onAnimationUpdate(ValueAnimator animation) { mCurrentTargetOffsetTop = (int) animation.getAnimatedValue() - mRefreshView.getMeasuredHeight(); + if (mRefreshView.getMeasuredHeight() > 0) { + mRefreshView.setPullingDistance(DoricUtils.px2dp(mRefreshView.getBottom())); + } mRefreshView.requestLayout(); } }); @@ -320,36 +335,13 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop); mNotify = false; - startScaleUpAnimation(mRefreshListener); + mRefreshView.setVisibility(View.VISIBLE); + onRefreshAnimationEnd(); } else { 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) { if (mRefreshing != refreshing) { @@ -359,24 +351,11 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent if (mRefreshing) { animateOffsetToCorrectPosition(mCurrentTargetOffsetTop, mRefreshListener); } 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 * progress. @@ -744,24 +723,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } else { // cancel refresh mRefreshing = false; - Animation.AnimationListener listener = 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); + animateOffsetToStartPosition(mCurrentTargetOffsetTop, null); } } @@ -912,7 +874,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent ViewCompat.offsetTopAndBottom(mRefreshView, offset); mCurrentTargetOffsetTop = mRefreshView.getTop(); if (mRefreshView.getMeasuredHeight() > 0) { - mRefreshView.setProgressRotation((float) mRefreshView.getBottom() / (float) mRefreshView.getMeasuredHeight() * 2); + mRefreshView.setPullingDistance(DoricUtils.px2dp(mRefreshView.getBottom())); } } diff --git a/Android/doric/src/main/java/pub/doric/refresh/PullingListener.java b/Android/doric/src/main/java/pub/doric/refresh/PullingListener.java index c09ab2c4..16a2c69d 100644 --- a/Android/doric/src/main/java/pub/doric/refresh/PullingListener.java +++ b/Android/doric/src/main/java/pub/doric/refresh/PullingListener.java @@ -16,5 +16,5 @@ public interface PullingListener { * * @param rotation Rotation is from [0..2] */ - void setProgressRotation(float rotation); + void setPullingDistance(float rotation); } diff --git a/Android/doric/src/main/java/pub/doric/refresh/RefreshableNode.java b/Android/doric/src/main/java/pub/doric/refresh/RefreshableNode.java index 18a72a8f..a073803b 100644 --- a/Android/doric/src/main/java/pub/doric/refresh/RefreshableNode.java +++ b/Android/doric/src/main/java/pub/doric/refresh/RefreshableNode.java @@ -33,7 +33,7 @@ public class RefreshableNode extends SuperNode implements Pull @Override protected DoricSwipeLayout build() { DoricSwipeLayout doricSwipeLayout = new DoricSwipeLayout(getContext()); - doricSwipeLayout.getRefreshView().setPullingListenr(this); + doricSwipeLayout.getRefreshView().setPullingListener(this); return doricSwipeLayout; } @@ -188,9 +188,9 @@ public class RefreshableNode extends SuperNode implements Pull } @Override - public void setProgressRotation(float rotation) { + public void setPullingDistance(float rotation) { if (mHeaderNode != null) { - mHeaderNode.callJSResponse("setProgressRotation", rotation); + mHeaderNode.callJSResponse("setPullingDistance", rotation); } } } diff --git a/demo/index.ts b/demo/index.ts index e9c37c1c..bd7e494d 100644 --- a/demo/index.ts +++ b/demo/index.ts @@ -17,4 +17,5 @@ export default [ 'src/PopoverDemo', 'src/AnimatorDemo', 'src/ComplicatedAnimations', + 'src/ComplicatedDemo', ] \ No newline at end of file diff --git a/demo/src/ComplicatedAnimations.ts b/demo/src/ComplicatedAnimations.ts index 75cdca97..bc477830 100644 --- a/demo/src/ComplicatedAnimations.ts +++ b/demo/src/ComplicatedAnimations.ts @@ -17,11 +17,12 @@ function thisLabel(str: string) { class AnimationDemo extends Panel { build(rootView: Group): void { const view = box(2) + const view2 = box(3) view.onClick = () => { modal(context).toast('Clicked') } vlayout([ - title("Complicated Animation"), + title("Complicated Animation"), vlayout( [ hlayout([ @@ -177,7 +178,17 @@ class AnimationDemo extends Panel { ] ).apply({ space: 10 } as IVLayout), 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({ layoutConfig: layoutConfig().atmost(), backgroundColor: colors[1].alpha(0.3 * 255), diff --git a/demo/src/ComplicatedDemo.ts b/demo/src/ComplicatedDemo.ts new file mode 100644 index 00000000..c4c4db2f --- /dev/null +++ b/demo/src/ComplicatedDemo.ts @@ -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) + } +} \ No newline at end of file diff --git a/demo/src/RefreshableDemo.ts b/demo/src/RefreshableDemo.ts index ea8cfd75..b91c7e02 100644 --- a/demo/src/RefreshableDemo.ts +++ b/demo/src/RefreshableDemo.ts @@ -31,8 +31,8 @@ class RefreshableDemo extends Panel { stopAnimation: () => { log('stopAnimation') }, - setProgressRotation: (rotation: number) => { - refreshImage.rotation = rotation + setPullingDistance: (distance: number) => { + refreshImage.rotation = distance / 30 }, }), content: (vlayout([ @@ -83,18 +83,6 @@ class RefreshableDemo extends Panel { refreshView.setRefreshable(context, false) } } 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({ layoutConfig: layoutConfig().atmost().h(LayoutSpec.WRAP_CONTENT), gravity: gravity().centerX(), diff --git a/demo/src/utils.ts b/demo/src/utils.ts index a9ac549a..9e7e7610 100644 --- a/demo/src/utils.ts +++ b/demo/src/utils.ts @@ -65,8 +65,8 @@ export function rotatedArrow(context: BridgeContext) { stopAnimation: () => { log('stopAnimation') }, - setProgressRotation: (rotation: number) => { - refreshImage.rotation = rotation + setPullingDistance: (distance: number) => { + refreshImage.rotation = distance / 30 }, }) } \ No newline at end of file diff --git a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m index 289e4443..282fb4fc 100644 --- a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m +++ b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m @@ -152,13 +152,13 @@ - (void)stopAnimation { [self.headerNode callJSResponse:@"stopAnimation", nil]; } -- (void)setProgressRotation:(CGFloat)rotation { - [self.headerNode callJSResponse:@"setProgressRotation", @(rotation), nil]; +- (void)setPullingDistance:(CGFloat)distance { + [self.headerNode callJSResponse:@"setPullingDistance", @(distance), nil]; } - (void)setRefreshing:(NSNumber *)refreshable withPromise:(DoricPromise *)promise { self.view.refreshing = [refreshable boolValue]; - [promise resolve:nil]; + [promise resolve:nil]; } - (void)setRefreshable:(NSNumber *)refreshing withPromise:(DoricPromise *)promise { diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h index f24a0edb..637b2378 100644 --- a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h @@ -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. // @@ -24,7 +9,7 @@ - (void)stopAnimation; -- (void)setProgressRotation:(CGFloat)rotation; +- (void)setPullingDistance:(CGFloat)rotation; @end @interface DoricSwipeRefreshLayout : UIScrollView diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m index fcc5eb4d..25def1a5 100644 --- a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m @@ -68,7 +68,14 @@ - (BOOL)requestFromSubview:(UIView *)subview { return [super requestFromSubview:subview]; } +- (void)layoutSubviews { + [super layoutSubviews]; +} + - (void)layoutSelf:(CGSize)targetSize { + if (self.contentOffset.y != 0) { + return; + } self.width = targetSize.width; self.height = targetSize.height; [self.headerView also:^(UIView *it) { @@ -109,7 +116,7 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 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; } if (refreshing) { + [self setContentOffset:CGPointMake(0, -self.headerView.height) animated:YES]; + self.scrollEnabled = NO; if (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 { - self.bounces = YES; - [UIView animateWithDuration:.3f - animations:^{ - self.contentOffset = (CGPoint) {0, 0}; - self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); - } - completion:^(BOOL finished) { - [self.swipePullingDelegate stopAnimation]; - self.scrollEnabled = YES; - } - ]; + [self setContentOffset:(CGPoint) {0, 0} animated:YES]; + self.scrollEnabled = YES; } _refreshing = refreshing; } diff --git a/js-framework/src/widget/refreshable.ts b/js-framework/src/widget/refreshable.ts index 527e2cd0..41746ec4 100644 --- a/js-framework/src/widget/refreshable.ts +++ b/js-framework/src/widget/refreshable.ts @@ -62,13 +62,13 @@ export function refreshable(config: IRefreshable) { export interface IPullable { startAnimation(): void stopAnimation(): void - setProgressRotation(rotation: number): void + setPullingDistance(distance: number): void } export function pullable(context: BridgeContext, v: View, config: IPullable) { Reflect.set(v, 'startAnimation', config.startAnimation) Reflect.set(v, 'stopAnimation', config.stopAnimation) - Reflect.set(v, 'setProgressRotation', config.setProgressRotation) + Reflect.set(v, 'setPullingDistance', config.setPullingDistance) return v } \ No newline at end of file