From d3b2d4c8bd36421f49f05141eb0f99b2ee83ac07 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Mon, 25 Nov 2019 17:15:43 +0800 Subject: [PATCH 01/35] feat:add SwipeLayout --- Android/app/build.gradle | 1 + Android/app/src/main/AndroidManifest.xml | 2 + .../java/pub/doric/demo/MainActivity.java | 6 + .../java/pub/doric/demo/PullableActivity.java | 28 + .../src/main/res/layout/activity_pullable.xml | 13 + .../pub/doric/pullable/CircleImageView.java | 159 +++ .../pub/doric/pullable/DoricRefreshView.java | 80 ++ .../pub/doric/pullable/DoricSwipeLayout.java | 1182 +++++++++++++++++ .../java/pub/doric/pullable/IPullable.java | 27 + 9 files changed, 1498 insertions(+) create mode 100644 Android/app/src/main/java/pub/doric/demo/PullableActivity.java create mode 100644 Android/app/src/main/res/layout/activity_pullable.xml create mode 100644 Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java create mode 100644 Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java create mode 100644 Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java create mode 100644 Android/doric/src/main/java/pub/doric/pullable/IPullable.java diff --git a/Android/app/build.gradle b/Android/app/build.gradle index 8f3a79bd..30ec9d1a 100644 --- a/Android/app/build.gradle +++ b/Android/app/build.gradle @@ -27,6 +27,7 @@ dependencies { implementation 'com.github.bumptech.glide:glide:4.10.0' implementation 'com.github.bumptech.glide:annotations:4.10.0' implementation 'com.github.penfeizhou.android.animation:glide-plugin:1.3.1' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0' debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-4' } diff --git a/Android/app/src/main/AndroidManifest.xml b/Android/app/src/main/AndroidManifest.xml index 36ce1127..3988de39 100644 --- a/Android/app/src/main/AndroidManifest.xml +++ b/Android/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="pub.doric.demo"> + + diff --git a/Android/app/src/main/java/pub/doric/demo/MainActivity.java b/Android/app/src/main/java/pub/doric/demo/MainActivity.java index ad23198d..4eaf9ad9 100644 --- a/Android/app/src/main/java/pub/doric/demo/MainActivity.java +++ b/Android/app/src/main/java/pub/doric/demo/MainActivity.java @@ -48,6 +48,7 @@ public class MainActivity extends AppCompatActivity { try { String[] demos = getAssets().list("demo"); List ret = new ArrayList<>(); + ret.add("Test"); for (String str : demos) { if (str.endsWith("js")) { ret.add(str); @@ -91,6 +92,11 @@ public class MainActivity extends AppCompatActivity { tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + if (data[position].contains("Test")) { + Intent intent = new Intent(tv.getContext(), PullableActivity.class); + tv.getContext().startActivity(intent); + return; + } if (data[position].contains("NavigatorDemo")) { Intent intent = new Intent(tv.getContext(), DoricActivity.class); intent.putExtra("scheme", "assets://demo/" + data[position]); diff --git a/Android/app/src/main/java/pub/doric/demo/PullableActivity.java b/Android/app/src/main/java/pub/doric/demo/PullableActivity.java new file mode 100644 index 00000000..615f27c5 --- /dev/null +++ b/Android/app/src/main/java/pub/doric/demo/PullableActivity.java @@ -0,0 +1,28 @@ +package pub.doric.demo; + +import androidx.appcompat.app.AppCompatActivity; + +import android.graphics.Color; +import android.os.Bundle; +import android.widget.FrameLayout; + +import pub.doric.pullable.DoricSwipeLayout; + +public class PullableActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_pullable); + final DoricSwipeLayout swipeRefreshLayout = findViewById(R.id.swipe_layout); + FrameLayout frameLayout = new FrameLayout(this); + frameLayout.setBackgroundColor(Color.YELLOW); + swipeRefreshLayout.addView(frameLayout); + swipeRefreshLayout.setOnRefreshListener(new DoricSwipeLayout.OnRefreshListener() { + @Override + public void onRefresh() { + swipeRefreshLayout.setRefreshing(false); + } + }); + } +} diff --git a/Android/app/src/main/res/layout/activity_pullable.xml b/Android/app/src/main/res/layout/activity_pullable.xml new file mode 100644 index 00000000..e9bad365 --- /dev/null +++ b/Android/app/src/main/res/layout/activity_pullable.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java b/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java new file mode 100644 index 00000000..70f663dd --- /dev/null +++ b/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java @@ -0,0 +1,159 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * 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. + */ + +package pub.doric.pullable; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RadialGradient; +import android.graphics.Shader; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.OvalShape; +import android.view.View; +import android.view.animation.Animation; +import android.widget.ImageView; + +import androidx.core.content.ContextCompat; +import androidx.core.view.ViewCompat; + +/** + * Private class created to work around issues with AnimationListeners being + * called before the animation is actually complete and support shadows on older + * platforms. + */ +class CircleImageView extends ImageView { + + private static final int KEY_SHADOW_COLOR = 0x1E000000; + private static final int FILL_SHADOW_COLOR = 0x3D000000; + // PX + private static final float X_OFFSET = 0f; + private static final float Y_OFFSET = 1.75f; + private static final float SHADOW_RADIUS = 3.5f; + private static final int SHADOW_ELEVATION = 4; + + private Animation.AnimationListener mListener; + int mShadowRadius; + + CircleImageView(Context context, int color) { + super(context); + final float density = getContext().getResources().getDisplayMetrics().density; + final int shadowYOffset = (int) (density * Y_OFFSET); + final int shadowXOffset = (int) (density * X_OFFSET); + + mShadowRadius = (int) (density * SHADOW_RADIUS); + + ShapeDrawable circle; + if (elevationSupported()) { + circle = new ShapeDrawable(new OvalShape()); + ViewCompat.setElevation(this, SHADOW_ELEVATION * density); + } else { + OvalShape oval = new OvalShadow(mShadowRadius); + circle = new ShapeDrawable(oval); + setLayerType(View.LAYER_TYPE_SOFTWARE, circle.getPaint()); + circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset, + KEY_SHADOW_COLOR); + final int padding = mShadowRadius; + // set padding so the inner image sits correctly within the shadow. + setPadding(padding, padding, padding, padding); + } + circle.getPaint().setColor(color); + ViewCompat.setBackground(this, circle); + } + + private boolean elevationSupported() { + return android.os.Build.VERSION.SDK_INT >= 21; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (!elevationSupported()) { + setMeasuredDimension(getMeasuredWidth() + mShadowRadius * 2, getMeasuredHeight() + + mShadowRadius * 2); + } + } + + public void setAnimationListener(Animation.AnimationListener listener) { + mListener = listener; + } + + @Override + public void onAnimationStart() { + super.onAnimationStart(); + if (mListener != null) { + mListener.onAnimationStart(getAnimation()); + } + } + + @Override + public void onAnimationEnd() { + super.onAnimationEnd(); + if (mListener != null) { + mListener.onAnimationEnd(getAnimation()); + } + } + + /** + * Update the background color of the circle image view. + * + * @param colorRes Id of a color resource. + */ + public void setBackgroundColorRes(int colorRes) { + setBackgroundColor(ContextCompat.getColor(getContext(), colorRes)); + } + + @Override + public void setBackgroundColor(int color) { + if (getBackground() instanceof ShapeDrawable) { + ((ShapeDrawable) getBackground()).getPaint().setColor(color); + } + } + + private class OvalShadow extends OvalShape { + private RadialGradient mRadialGradient; + private Paint mShadowPaint; + + OvalShadow(int shadowRadius) { + super(); + mShadowPaint = new Paint(); + mShadowRadius = shadowRadius; + updateRadialGradient((int) rect().width()); + } + + @Override + protected void onResize(float width, float height) { + super.onResize(width, height); + updateRadialGradient((int) width); + } + + @Override + public void draw(Canvas canvas, Paint paint) { + final int viewWidth = CircleImageView.this.getWidth(); + final int viewHeight = CircleImageView.this.getHeight(); + canvas.drawCircle(viewWidth / 2, viewHeight / 2, viewWidth / 2, mShadowPaint); + canvas.drawCircle(viewWidth / 2, viewHeight / 2, viewWidth / 2 - mShadowRadius, paint); + } + + private void updateRadialGradient(int diameter) { + mRadialGradient = new RadialGradient(diameter / 2, diameter / 2, + mShadowRadius, new int[]{FILL_SHADOW_COLOR, Color.TRANSPARENT}, + null, Shader.TileMode.CLAMP); + mShadowPaint.setShader(mRadialGradient); + } + } +} diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java b/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java new file mode 100644 index 00000000..90e376f2 --- /dev/null +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java @@ -0,0 +1,80 @@ +package pub.doric.pullable; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.annotation.AttrRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * @Description: pub.doric.pullable + * @Author: pengfei.zhou + * @CreateDate: 2019-11-25 + */ +public class DoricRefreshView extends FrameLayout implements IPullable { + private View content; + + public DoricRefreshView(@NonNull Context context) { + super(context); + } + + public DoricRefreshView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public DoricRefreshView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setContent(View v) { + removeAllViews(); + content = v; + if (v.getLayoutParams() instanceof FrameLayout.LayoutParams) { + ((LayoutParams) v.getLayoutParams()).gravity = Gravity.BOTTOM; + } else { + LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + params.gravity = Gravity.CENTER; + v.setLayoutParams(params); + } + addView(v); + } + + public View getContent() { + return content; + } + + @Override + public void startAnimation() { + if (content != null && content instanceof IPullable) { + ((IPullable) content).startAnimation(); + } + } + + @Override + public void stopAnimation() { + if (content != null && content instanceof IPullable) { + ((IPullable) content).stopAnimation(); + } + } + + @Override + public int successAnimation() { + if (content != null && content instanceof IPullable) { + return ((IPullable) content).successAnimation(); + } else { + return 0; + } + } + + @Override + public void setProgressRotation(float rotation) { + if (content != null && content instanceof IPullable) { + ((IPullable) content).setProgressRotation(rotation); + } + } +} \ No newline at end of file diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java new file mode 100644 index 00000000..d128dc6e --- /dev/null +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java @@ -0,0 +1,1182 @@ +package pub.doric.pullable; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Transformation; +import android.widget.AbsListView; +import android.widget.ListView; + +import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Px; +import androidx.annotation.VisibleForTesting; +import androidx.core.content.ContextCompat; +import androidx.core.view.NestedScrollingChild; +import androidx.core.view.NestedScrollingChildHelper; +import androidx.core.view.NestedScrollingParent; +import androidx.core.view.NestedScrollingParentHelper; +import androidx.core.view.ViewCompat; +import androidx.core.widget.ListViewCompat; +import androidx.swiperefreshlayout.widget.CircularProgressDrawable; + +import android.view.animation.Animation.AnimationListener; + +/** + * @Description: pub.doric.pullable + * @Author: pengfei.zhou + * @CreateDate: 2019-11-25 + */ +public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent, + NestedScrollingChild { + // Maps to ProgressBar.Large style + public static final int LARGE = CircularProgressDrawable.LARGE; + // Maps to ProgressBar default style + public static final int DEFAULT = CircularProgressDrawable.DEFAULT; + + public static final int DEFAULT_SLINGSHOT_DISTANCE = -1; + + @VisibleForTesting + static final int CIRCLE_DIAMETER = 40; + @VisibleForTesting + static final int CIRCLE_DIAMETER_LARGE = 56; + + private static final String LOG_TAG = androidx.swiperefreshlayout.widget.SwipeRefreshLayout.class.getSimpleName(); + + private static final int MAX_ALPHA = 255; + private static final int STARTING_PROGRESS_ALPHA = (int) (.3f * MAX_ALPHA); + + private static final float DECELERATE_INTERPOLATION_FACTOR = 2f; + private static final int INVALID_POINTER = -1; + private static final float DRAG_RATE = .5f; + + // Max amount of circle that can be filled by progress during swipe gesture, + // where 1.0 is a full circle + private static final float MAX_PROGRESS_ANGLE = .8f; + + private static final int SCALE_DOWN_DURATION = 150; + + private static final int ALPHA_ANIMATION_DURATION = 300; + + private static final int ANIMATE_TO_TRIGGER_DURATION = 200; + + private static final int ANIMATE_TO_START_DURATION = 200; + + // Default background for the progress spinner + private static final int CIRCLE_BG_LIGHT = 0xFFFAFAFA; + // Default offset in dips from the top of the view to where the progress spinner should stop + private static final int DEFAULT_CIRCLE_TARGET = 64; + + private View mTarget; // the target of the gesture + OnRefreshListener mListener; + boolean mRefreshing = false; + private int mTouchSlop; + private float mTotalDragDistance = -1; + + // If nested scrolling is enabled, the total amount that needed to be + // consumed by this as the nested scrolling parent is used in place of the + // overscroll determined by MOVE events in the onTouch handler + private float mTotalUnconsumed; + private final NestedScrollingParentHelper mNestedScrollingParentHelper; + private final NestedScrollingChildHelper mNestedScrollingChildHelper; + private final int[] mParentScrollConsumed = new int[2]; + private final int[] mParentOffsetInWindow = new int[2]; + private boolean mNestedScrollInProgress; + + private int mMediumAnimationDuration; + int mCurrentTargetOffsetTop; + + private float mInitialMotionY; + private float mInitialDownY; + private boolean mIsBeingDragged; + private int mActivePointerId = INVALID_POINTER; + // Whether this item is scaled up rather than clipped + boolean mScale; + + // Target is returning to its start offset because it was cancelled or a + // refresh was triggered. + private boolean mReturningToStart; + private final DecelerateInterpolator mDecelerateInterpolator; + private static final int[] LAYOUT_ATTRS = new int[]{ + android.R.attr.enabled + }; + + CircleImageView mCircleView; + private int mCircleViewIndex = -1; + + protected int mFrom; + + float mStartingScale; + + protected int mOriginalOffsetTop; + + int mSpinnerOffsetEnd; + + int mCustomSlingshotDistance; + + CircularProgressDrawable mProgress; + + private Animation mScaleAnimation; + + private Animation mScaleDownAnimation; + + private Animation mAlphaStartAnimation; + + private Animation mAlphaMaxAnimation; + + private Animation mScaleDownToStartAnimation; + + boolean mNotify; + + private int mCircleDiameter; + + // Whether the client has set a custom starting position; + boolean mUsingCustomStart; + + private OnChildScrollUpCallback mChildScrollUpCallback; + + private AnimationListener mRefreshListener = new AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + if (mRefreshing) { + // Make sure the progress view is fully visible + mProgress.setAlpha(MAX_ALPHA); + mProgress.start(); + if (mNotify) { + if (mListener != null) { + mListener.onRefresh(); + } + } + mCurrentTargetOffsetTop = mCircleView.getTop(); + } else { + reset(); + } + } + }; + + void reset() { + mCircleView.clearAnimation(); + mProgress.stop(); + mCircleView.setVisibility(View.GONE); + setColorViewAlpha(MAX_ALPHA); + // Return the circle to its start position + if (mScale) { + setAnimationProgress(0 /* animation complete and view is hidden */); + } else { + setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop); + } + mCurrentTargetOffsetTop = mCircleView.getTop(); + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + if (!enabled) { + reset(); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + reset(); + } + + private void setColorViewAlpha(int targetAlpha) { + mCircleView.getBackground().setAlpha(targetAlpha); + mProgress.setAlpha(targetAlpha); + } + + /** + * The refresh indicator starting and resting position is always positioned + * near the top of the refreshing content. This position is a consistent + * location, but can be adjusted in either direction based on whether or not + * there is a toolbar or actionbar present. + *

+ * Note: Calling this will reset the position of the refresh indicator to + * start. + *

+ * + * @param scale Set to true if there is no view at a higher z-order than where the progress + * spinner is set to appear. Setting it to true will cause indicator to be scaled + * up rather than clipped. + * @param start The offset in pixels from the top of this view at which the + * progress spinner should appear. + * @param end The offset in pixels from the top of this view at which the + * progress spinner should come to rest after a successful swipe + * gesture. + */ + public void setProgressViewOffset(boolean scale, int start, int end) { + mScale = scale; + mOriginalOffsetTop = start; + mSpinnerOffsetEnd = end; + mUsingCustomStart = true; + reset(); + mRefreshing = false; + } + + /** + * @return The offset in pixels from the top of this view at which the progress spinner should + * appear. + */ + public int getProgressViewStartOffset() { + return mOriginalOffsetTop; + } + + /** + * @return The offset in pixels from the top of this view at which the progress spinner should + * come to rest after a successful swipe gesture. + */ + public int getProgressViewEndOffset() { + return mSpinnerOffsetEnd; + } + + /** + * The refresh indicator resting position is always positioned near the top + * of the refreshing content. This position is a consistent location, but + * can be adjusted in either direction based on whether or not there is a + * toolbar or actionbar present. + * + * @param scale Set to true if there is no view at a higher z-order than where the progress + * spinner is set to appear. Setting it to true will cause indicator to be scaled + * up rather than clipped. + * @param end The offset in pixels from the top of this view at which the + * progress spinner should come to rest after a successful swipe + * gesture. + */ + public void setProgressViewEndTarget(boolean scale, int end) { + mSpinnerOffsetEnd = end; + mScale = scale; + mCircleView.invalidate(); + } + + /** + * Sets a custom slingshot distance. + * + * @param slingshotDistance The distance in pixels that the refresh indicator can be pulled + * beyond its resting position. Use + * {@link #DEFAULT_SLINGSHOT_DISTANCE} to reset to the default value. + */ + public void setSlingshotDistance(@Px int slingshotDistance) { + mCustomSlingshotDistance = slingshotDistance; + } + + /** + * One of DEFAULT, or LARGE. + */ + public void setSize(int size) { + if (size != CircularProgressDrawable.LARGE && size != CircularProgressDrawable.DEFAULT) { + return; + } + final DisplayMetrics metrics = getResources().getDisplayMetrics(); + if (size == CircularProgressDrawable.LARGE) { + mCircleDiameter = (int) (CIRCLE_DIAMETER_LARGE * metrics.density); + } else { + mCircleDiameter = (int) (CIRCLE_DIAMETER * metrics.density); + } + // force the bounds of the progress circle inside the circle view to + // update by setting it to null before updating its size and then + // re-setting it + mCircleView.setImageDrawable(null); + mProgress.setStyle(size); + mCircleView.setImageDrawable(mProgress); + } + + /** + * Simple constructor to use when creating a SwipeRefreshLayout from code. + * + * @param context + */ + public DoricSwipeLayout(@NonNull Context context) { + this(context, null); + } + + /** + * Constructor that is called when inflating SwipeRefreshLayout from XML. + * + * @param context + * @param attrs + */ + public DoricSwipeLayout(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + + mMediumAnimationDuration = getResources().getInteger( + android.R.integer.config_mediumAnimTime); + + setWillNotDraw(false); + mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR); + + final DisplayMetrics metrics = getResources().getDisplayMetrics(); + mCircleDiameter = (int) (CIRCLE_DIAMETER * metrics.density); + + createProgressView(); + setChildrenDrawingOrderEnabled(true); + // the absolute offset has to take into account that the circle starts at an offset + mSpinnerOffsetEnd = (int) (DEFAULT_CIRCLE_TARGET * metrics.density); + mTotalDragDistance = mSpinnerOffsetEnd; + mNestedScrollingParentHelper = new NestedScrollingParentHelper(this); + + mNestedScrollingChildHelper = new NestedScrollingChildHelper(this); + setNestedScrollingEnabled(true); + + mOriginalOffsetTop = mCurrentTargetOffsetTop = -mCircleDiameter; + moveToStart(1.0f); + + final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); + setEnabled(a.getBoolean(0, true)); + a.recycle(); + } + + @Override + protected int getChildDrawingOrder(int childCount, int i) { + if (mCircleViewIndex < 0) { + return i; + } else if (i == childCount - 1) { + // Draw the selected child last + return mCircleViewIndex; + } else if (i >= mCircleViewIndex) { + // Move the children after the selected child earlier one + return i + 1; + } else { + // Keep the children before the selected child the same + return i; + } + } + + private void createProgressView() { + mCircleView = new CircleImageView(getContext(), CIRCLE_BG_LIGHT); + mProgress = new CircularProgressDrawable(getContext()); + mProgress.setStyle(CircularProgressDrawable.DEFAULT); + mCircleView.setImageDrawable(mProgress); + mCircleView.setVisibility(View.GONE); + addView(mCircleView); + } + + /** + * Set the listener to be notified when a refresh is triggered via the swipe + * gesture. + */ + public void setOnRefreshListener(@Nullable OnRefreshListener listener) { + mListener = listener; + } + + /** + * Notify the widget that refresh state has changed. Do not call this when + * refresh is triggered by a swipe gesture. + * + * @param refreshing Whether or not the view should show refresh progress. + */ + public void setRefreshing(boolean refreshing) { + if (refreshing && mRefreshing != refreshing) { + // scale and show + mRefreshing = refreshing; + int endTarget = 0; + if (!mUsingCustomStart) { + endTarget = mSpinnerOffsetEnd + mOriginalOffsetTop; + } else { + endTarget = mSpinnerOffsetEnd; + } + setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop); + mNotify = false; + startScaleUpAnimation(mRefreshListener); + } else { + setRefreshing(refreshing, false /* notify */); + } + } + + private void startScaleUpAnimation(AnimationListener listener) { + mCircleView.setVisibility(View.VISIBLE); + mProgress.setAlpha(MAX_ALPHA); + mScaleAnimation = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + setAnimationProgress(interpolatedTime); + } + }; + mScaleAnimation.setDuration(mMediumAnimationDuration); + if (listener != null) { + mCircleView.setAnimationListener(listener); + } + mCircleView.clearAnimation(); + mCircleView.startAnimation(mScaleAnimation); + } + + /** + * Pre API 11, this does an alpha animation. + * + * @param progress + */ + void setAnimationProgress(float progress) { + mCircleView.setScaleX(progress); + mCircleView.setScaleY(progress); + } + + private void setRefreshing(boolean refreshing, final boolean notify) { + if (mRefreshing != refreshing) { + mNotify = notify; + ensureTarget(); + mRefreshing = refreshing; + if (mRefreshing) { + animateOffsetToCorrectPosition(mCurrentTargetOffsetTop, mRefreshListener); + } else { + startScaleDownAnimation(mRefreshListener); + } + } + } + + void startScaleDownAnimation(Animation.AnimationListener listener) { + mScaleDownAnimation = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + setAnimationProgress(1 - interpolatedTime); + } + }; + mScaleDownAnimation.setDuration(SCALE_DOWN_DURATION); + mCircleView.setAnimationListener(listener); + mCircleView.clearAnimation(); + mCircleView.startAnimation(mScaleDownAnimation); + } + + private void startProgressAlphaStartAnimation() { + mAlphaStartAnimation = startAlphaAnimation(mProgress.getAlpha(), STARTING_PROGRESS_ALPHA); + } + + private void startProgressAlphaMaxAnimation() { + mAlphaMaxAnimation = startAlphaAnimation(mProgress.getAlpha(), MAX_ALPHA); + } + + private Animation startAlphaAnimation(final int startingAlpha, final int endingAlpha) { + Animation alpha = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + mProgress.setAlpha( + (int) (startingAlpha + ((endingAlpha - startingAlpha) * interpolatedTime))); + } + }; + alpha.setDuration(ALPHA_ANIMATION_DURATION); + // Clear out the previous animation listeners. + mCircleView.setAnimationListener(null); + mCircleView.clearAnimation(); + mCircleView.startAnimation(alpha); + return alpha; + } + + /** + * @deprecated Use {@link #setProgressBackgroundColorSchemeResource(int)} + */ + @Deprecated + public void setProgressBackgroundColor(int colorRes) { + setProgressBackgroundColorSchemeResource(colorRes); + } + + /** + * Set the background color of the progress spinner disc. + * + * @param colorRes Resource id of the color. + */ + public void setProgressBackgroundColorSchemeResource(@ColorRes int colorRes) { + setProgressBackgroundColorSchemeColor(ContextCompat.getColor(getContext(), colorRes)); + } + + /** + * Set the background color of the progress spinner disc. + * + * @param color + */ + public void setProgressBackgroundColorSchemeColor(@ColorInt int color) { + mCircleView.setBackgroundColor(color); + } + + /** + * @deprecated Use {@link #setColorSchemeResources(int...)} + */ + @Deprecated + public void setColorScheme(@ColorRes int... colors) { + setColorSchemeResources(colors); + } + + /** + * Set the color resources used in the progress animation from color resources. + * The first color will also be the color of the bar that grows in response + * to a user swipe gesture. + * + * @param colorResIds + */ + public void setColorSchemeResources(@ColorRes int... colorResIds) { + final Context context = getContext(); + int[] colorRes = new int[colorResIds.length]; + for (int i = 0; i < colorResIds.length; i++) { + colorRes[i] = ContextCompat.getColor(context, colorResIds[i]); + } + setColorSchemeColors(colorRes); + } + + /** + * Set the colors used in the progress animation. The first + * color will also be the color of the bar that grows in response to a user + * swipe gesture. + * + * @param colors + */ + public void setColorSchemeColors(@ColorInt int... colors) { + ensureTarget(); + mProgress.setColorSchemeColors(colors); + } + + /** + * @return Whether the SwipeRefreshWidget is actively showing refresh + * progress. + */ + public boolean isRefreshing() { + return mRefreshing; + } + + private void ensureTarget() { + // Don't bother getting the parent height if the parent hasn't been laid + // out yet. + if (mTarget == null) { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (!child.equals(mCircleView)) { + mTarget = child; + break; + } + } + } + } + + /** + * Set the distance to trigger a sync in dips + * + * @param distance + */ + public void setDistanceToTriggerSync(int distance) { + mTotalDragDistance = distance; + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final int width = getMeasuredWidth(); + final int height = getMeasuredHeight(); + if (getChildCount() == 0) { + return; + } + if (mTarget == null) { + ensureTarget(); + } + if (mTarget == null) { + return; + } + final View child = mTarget; + final int childLeft = getPaddingLeft(); + final int childTop = getPaddingTop(); + final int childWidth = width - getPaddingLeft() - getPaddingRight(); + final int childHeight = height - getPaddingTop() - getPaddingBottom(); + child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); + int circleWidth = mCircleView.getMeasuredWidth(); + int circleHeight = mCircleView.getMeasuredHeight(); + mCircleView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop, + (width / 2 + circleWidth / 2), mCurrentTargetOffsetTop + circleHeight); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (mTarget == null) { + ensureTarget(); + } + if (mTarget == null) { + return; + } + mTarget.measure(MeasureSpec.makeMeasureSpec( + getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), + MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec( + getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY)); + mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY)); + mCircleViewIndex = -1; + // Get the index of the circleview. + for (int index = 0; index < getChildCount(); index++) { + if (getChildAt(index) == mCircleView) { + mCircleViewIndex = index; + break; + } + } + } + + /** + * Get the diameter of the progress circle that is displayed as part of the + * swipe to refresh layout. + * + * @return Diameter in pixels of the progress circle view. + */ + public int getProgressCircleDiameter() { + return mCircleDiameter; + } + + /** + * @return Whether it is possible for the child view of this layout to + * scroll up. Override this if the child view is a custom view. + */ + public boolean canChildScrollUp() { + if (mChildScrollUpCallback != null) { + return mChildScrollUpCallback.canChildScrollUp(this, mTarget); + } + if (mTarget instanceof ListView) { + return ListViewCompat.canScrollList((ListView) mTarget, -1); + } + return mTarget.canScrollVertically(-1); + } + + /** + * Set a callback to override {@link androidx.swiperefreshlayout.widget.SwipeRefreshLayout#canChildScrollUp()} method. Non-null + * callback will return the value provided by the callback and ignore all internal logic. + * + * @param callback Callback that should be called when canChildScrollUp() is called. + */ + public void setOnChildScrollUpCallback(@Nullable OnChildScrollUpCallback callback) { + mChildScrollUpCallback = callback; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + ensureTarget(); + + final int action = ev.getActionMasked(); + int pointerIndex; + + if (mReturningToStart && action == MotionEvent.ACTION_DOWN) { + mReturningToStart = false; + } + + if (!isEnabled() || mReturningToStart || canChildScrollUp() + || mRefreshing || mNestedScrollInProgress) { + // Fail fast if we're not in a state where a swipe is possible + return false; + } + + switch (action) { + case MotionEvent.ACTION_DOWN: + setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop()); + mActivePointerId = ev.getPointerId(0); + mIsBeingDragged = false; + + pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex < 0) { + return false; + } + mInitialDownY = ev.getY(pointerIndex); + break; + + case MotionEvent.ACTION_MOVE: + if (mActivePointerId == INVALID_POINTER) { + Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id."); + return false; + } + + pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex < 0) { + return false; + } + final float y = ev.getY(pointerIndex); + startDragging(y); + break; + + case MotionEvent.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mIsBeingDragged = false; + mActivePointerId = INVALID_POINTER; + break; + } + + return mIsBeingDragged; + } + + @Override + public void requestDisallowInterceptTouchEvent(boolean b) { + // if this is a List < L or another view that doesn't support nested + // scrolling, ignore this request so that the vertical scroll event + // isn't stolen + if ((android.os.Build.VERSION.SDK_INT < 21 && mTarget instanceof AbsListView) + || (mTarget != null && !ViewCompat.isNestedScrollingEnabled(mTarget))) { + // Nope. + } else { + super.requestDisallowInterceptTouchEvent(b); + } + } + + // NestedScrollingParent + + @Override + public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { + return isEnabled() && !mReturningToStart && !mRefreshing + && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; + } + + @Override + public void onNestedScrollAccepted(View child, View target, int axes) { + // Reset the counter of how much leftover scroll needs to be consumed. + mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes); + // Dispatch up to the nested parent + startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL); + mTotalUnconsumed = 0; + mNestedScrollInProgress = true; + } + + @Override + public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { + // If we are in the middle of consuming, a scroll, then we want to move the spinner back up + // before allowing the list to scroll + if (dy > 0 && mTotalUnconsumed > 0) { + if (dy > mTotalUnconsumed) { + consumed[1] = dy - (int) mTotalUnconsumed; + mTotalUnconsumed = 0; + } else { + mTotalUnconsumed -= dy; + consumed[1] = dy; + } + moveSpinner(mTotalUnconsumed); + } + + // If a client layout is using a custom start position for the circle + // view, they mean to hide it again before scrolling the child view + // If we get back to mTotalUnconsumed == 0 and there is more to go, hide + // the circle so it isn't exposed if its blocking content is moved + if (mUsingCustomStart && dy > 0 && mTotalUnconsumed == 0 + && Math.abs(dy - consumed[1]) > 0) { + mCircleView.setVisibility(View.GONE); + } + + // Now let our nested parent consume the leftovers + final int[] parentConsumed = mParentScrollConsumed; + if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) { + consumed[0] += parentConsumed[0]; + consumed[1] += parentConsumed[1]; + } + } + + @Override + public int getNestedScrollAxes() { + return mNestedScrollingParentHelper.getNestedScrollAxes(); + } + + @Override + public void onStopNestedScroll(View target) { + mNestedScrollingParentHelper.onStopNestedScroll(target); + mNestedScrollInProgress = false; + // Finish the spinner for nested scrolling if we ever consumed any + // unconsumed nested scroll + if (mTotalUnconsumed > 0) { + finishSpinner(mTotalUnconsumed); + mTotalUnconsumed = 0; + } + // Dispatch up our nested parent + stopNestedScroll(); + } + + @Override + public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed, + final int dxUnconsumed, final int dyUnconsumed) { + // Dispatch up to the nested parent first + dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, + mParentOffsetInWindow); + + // This is a bit of a hack. Nested scrolling works from the bottom up, and as we are + // sometimes between two nested scrolling views, we need a way to be able to know when any + // nested scrolling parent has stopped handling events. We do that by using the + // 'offset in window 'functionality to see if we have been moved from the event. + // This is a decent indication of whether we should take over the event stream or not. + final int dy = dyUnconsumed + mParentOffsetInWindow[1]; + if (dy < 0 && !canChildScrollUp()) { + mTotalUnconsumed += Math.abs(dy); + moveSpinner(mTotalUnconsumed); + } + } + + // NestedScrollingChild + + @Override + public void setNestedScrollingEnabled(boolean enabled) { + mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled); + } + + @Override + public boolean isNestedScrollingEnabled() { + return mNestedScrollingChildHelper.isNestedScrollingEnabled(); + } + + @Override + public boolean startNestedScroll(int axes) { + return mNestedScrollingChildHelper.startNestedScroll(axes); + } + + @Override + public void stopNestedScroll() { + mNestedScrollingChildHelper.stopNestedScroll(); + } + + @Override + public boolean hasNestedScrollingParent() { + return mNestedScrollingChildHelper.hasNestedScrollingParent(); + } + + @Override + public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, + int dyUnconsumed, int[] offsetInWindow) { + return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, + dxUnconsumed, dyUnconsumed, offsetInWindow); + } + + @Override + public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { + return mNestedScrollingChildHelper.dispatchNestedPreScroll( + dx, dy, consumed, offsetInWindow); + } + + @Override + public boolean onNestedPreFling(View target, float velocityX, + float velocityY) { + return dispatchNestedPreFling(velocityX, velocityY); + } + + @Override + public boolean onNestedFling(View target, float velocityX, float velocityY, + boolean consumed) { + return dispatchNestedFling(velocityX, velocityY, consumed); + } + + @Override + public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { + return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed); + } + + @Override + public boolean dispatchNestedPreFling(float velocityX, float velocityY) { + return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY); + } + + private boolean isAnimationRunning(Animation animation) { + return animation != null && animation.hasStarted() && !animation.hasEnded(); + } + + private void moveSpinner(float overscrollTop) { + mProgress.setArrowEnabled(true); + float originalDragPercent = overscrollTop / mTotalDragDistance; + + float dragPercent = Math.min(1f, Math.abs(originalDragPercent)); + float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3; + float extraOS = Math.abs(overscrollTop) - mTotalDragDistance; + float slingshotDist = mCustomSlingshotDistance > 0 + ? mCustomSlingshotDistance + : (mUsingCustomStart + ? mSpinnerOffsetEnd - mOriginalOffsetTop + : mSpinnerOffsetEnd); + float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2) + / slingshotDist); + float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow( + (tensionSlingshotPercent / 4), 2)) * 2f; + float extraMove = (slingshotDist) * tensionPercent * 2; + + int targetY = mOriginalOffsetTop + (int) ((slingshotDist * dragPercent) + extraMove); + // where 1.0f is a full circle + if (mCircleView.getVisibility() != View.VISIBLE) { + mCircleView.setVisibility(View.VISIBLE); + } + if (!mScale) { + mCircleView.setScaleX(1f); + mCircleView.setScaleY(1f); + } + + if (mScale) { + setAnimationProgress(Math.min(1f, overscrollTop / mTotalDragDistance)); + } + if (overscrollTop < mTotalDragDistance) { + if (mProgress.getAlpha() > STARTING_PROGRESS_ALPHA + && !isAnimationRunning(mAlphaStartAnimation)) { + // Animate the alpha + startProgressAlphaStartAnimation(); + } + } else { + if (mProgress.getAlpha() < MAX_ALPHA && !isAnimationRunning(mAlphaMaxAnimation)) { + // Animate the alpha + startProgressAlphaMaxAnimation(); + } + } + float strokeStart = adjustedPercent * .8f; + mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart)); + mProgress.setArrowScale(Math.min(1f, adjustedPercent)); + + float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f; + mProgress.setProgressRotation(rotation); + setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop); + } + + private void finishSpinner(float overscrollTop) { + if (overscrollTop > mTotalDragDistance) { + setRefreshing(true, true /* notify */); + } else { + // cancel refresh + mRefreshing = false; + mProgress.setStartEndTrim(0f, 0f); + Animation.AnimationListener listener = null; + if (!mScale) { + listener = new Animation.AnimationListener() { + + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + if (!mScale) { + startScaleDownAnimation(null); + } + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + + }; + } + animateOffsetToStartPosition(mCurrentTargetOffsetTop, listener); + mProgress.setArrowEnabled(false); + } + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + final int action = ev.getActionMasked(); + int pointerIndex = -1; + + if (mReturningToStart && action == MotionEvent.ACTION_DOWN) { + mReturningToStart = false; + } + + if (!isEnabled() || mReturningToStart || canChildScrollUp() + || mRefreshing || mNestedScrollInProgress) { + // Fail fast if we're not in a state where a swipe is possible + return false; + } + + switch (action) { + case MotionEvent.ACTION_DOWN: + mActivePointerId = ev.getPointerId(0); + mIsBeingDragged = false; + break; + + case MotionEvent.ACTION_MOVE: { + pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex < 0) { + Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id."); + return false; + } + + final float y = ev.getY(pointerIndex); + startDragging(y); + + if (mIsBeingDragged) { + final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE; + if (overscrollTop > 0) { + moveSpinner(overscrollTop); + } else { + return false; + } + } + break; + } + case MotionEvent.ACTION_POINTER_DOWN: { + pointerIndex = ev.getActionIndex(); + if (pointerIndex < 0) { + Log.e(LOG_TAG, + "Got ACTION_POINTER_DOWN event but have an invalid action index."); + return false; + } + mActivePointerId = ev.getPointerId(pointerIndex); + break; + } + + case MotionEvent.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + break; + + case MotionEvent.ACTION_UP: { + pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex < 0) { + Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id."); + return false; + } + + if (mIsBeingDragged) { + final float y = ev.getY(pointerIndex); + final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE; + mIsBeingDragged = false; + finishSpinner(overscrollTop); + } + mActivePointerId = INVALID_POINTER; + return false; + } + case MotionEvent.ACTION_CANCEL: + return false; + } + + return true; + } + + private void startDragging(float y) { + final float yDiff = y - mInitialDownY; + if (yDiff > mTouchSlop && !mIsBeingDragged) { + mInitialMotionY = mInitialDownY + mTouchSlop; + mIsBeingDragged = true; + mProgress.setAlpha(STARTING_PROGRESS_ALPHA); + } + } + + private void animateOffsetToCorrectPosition(int from, AnimationListener listener) { + mFrom = from; + mAnimateToCorrectPosition.reset(); + mAnimateToCorrectPosition.setDuration(ANIMATE_TO_TRIGGER_DURATION); + mAnimateToCorrectPosition.setInterpolator(mDecelerateInterpolator); + if (listener != null) { + mCircleView.setAnimationListener(listener); + } + mCircleView.clearAnimation(); + mCircleView.startAnimation(mAnimateToCorrectPosition); + } + + private void animateOffsetToStartPosition(int from, AnimationListener listener) { + if (mScale) { + // Scale the item back down + startScaleDownReturnToStartAnimation(from, listener); + } else { + mFrom = from; + mAnimateToStartPosition.reset(); + mAnimateToStartPosition.setDuration(ANIMATE_TO_START_DURATION); + mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator); + if (listener != null) { + mCircleView.setAnimationListener(listener); + } + mCircleView.clearAnimation(); + mCircleView.startAnimation(mAnimateToStartPosition); + } + } + + private final Animation mAnimateToCorrectPosition = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + int targetTop = 0; + int endTarget = 0; + if (!mUsingCustomStart) { + endTarget = mSpinnerOffsetEnd - Math.abs(mOriginalOffsetTop); + } else { + endTarget = mSpinnerOffsetEnd; + } + targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime)); + int offset = targetTop - mCircleView.getTop(); + setTargetOffsetTopAndBottom(offset); + mProgress.setArrowScale(1 - interpolatedTime); + } + }; + + void moveToStart(float interpolatedTime) { + int targetTop = 0; + targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime)); + int offset = targetTop - mCircleView.getTop(); + setTargetOffsetTopAndBottom(offset); + } + + private final Animation mAnimateToStartPosition = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + moveToStart(interpolatedTime); + } + }; + + private void startScaleDownReturnToStartAnimation(int from, + Animation.AnimationListener listener) { + mFrom = from; + mStartingScale = mCircleView.getScaleX(); + mScaleDownToStartAnimation = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + float targetScale = (mStartingScale + (-mStartingScale * interpolatedTime)); + setAnimationProgress(targetScale); + moveToStart(interpolatedTime); + } + }; + mScaleDownToStartAnimation.setDuration(SCALE_DOWN_DURATION); + if (listener != null) { + mCircleView.setAnimationListener(listener); + } + mCircleView.clearAnimation(); + mCircleView.startAnimation(mScaleDownToStartAnimation); + } + + void setTargetOffsetTopAndBottom(int offset) { + mCircleView.bringToFront(); + ViewCompat.offsetTopAndBottom(mCircleView, offset); + mCurrentTargetOffsetTop = mCircleView.getTop(); + } + + private void onSecondaryPointerUp(MotionEvent ev) { + final int pointerIndex = ev.getActionIndex(); + final int pointerId = ev.getPointerId(pointerIndex); + if (pointerId == mActivePointerId) { + // This was our active pointer going up. Choose a new + // active pointer and adjust accordingly. + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + mActivePointerId = ev.getPointerId(newPointerIndex); + } + } + + /** + * Classes that wish to be notified when the swipe gesture correctly + * triggers a refresh should implement this interface. + */ + public interface OnRefreshListener { + /** + * Called when a swipe gesture triggers a refresh. + */ + void onRefresh(); + } + + /** + * Classes that wish to override {@link androidx.swiperefreshlayout.widget.SwipeRefreshLayout#canChildScrollUp()} method + * behavior should implement this interface. + */ + public interface OnChildScrollUpCallback { + /** + * Callback that will be called when {@link androidx.swiperefreshlayout.widget.SwipeRefreshLayout#canChildScrollUp()} method + * is called to allow the implementer to override its behavior. + * + * @param parent SwipeRefreshLayout that this callback is overriding. + * @param child The child view of SwipeRefreshLayout. + * @return Whether it is possible for the child view of parent layout to scroll up. + */ + boolean canChildScrollUp(@NonNull DoricSwipeLayout parent, @Nullable View child); + } +} \ No newline at end of file diff --git a/Android/doric/src/main/java/pub/doric/pullable/IPullable.java b/Android/doric/src/main/java/pub/doric/pullable/IPullable.java new file mode 100644 index 00000000..83bb96af --- /dev/null +++ b/Android/doric/src/main/java/pub/doric/pullable/IPullable.java @@ -0,0 +1,27 @@ +package pub.doric.pullable; + +/** + * @Description: pub.doric.pullable + * @Author: pengfei.zhou + * @CreateDate: 2019-11-25 + */ +public interface IPullable { + + void startAnimation(); + + void stopAnimation(); + + /** + * run the animation after pull request success and before stop animation + * + * @return the duration of success animation or 0 if no success animation + */ + int successAnimation(); + + /** + * Set the amount of rotation to apply to the progress spinner. + * + * @param rotation Rotation is from [0..1] + */ + void setProgressRotation(float rotation); +} From a47b3682db9693dc9388a7cdd0a9bf3f1b148d13 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Mon, 25 Nov 2019 18:54:27 +0800 Subject: [PATCH 02/35] feat:fix shaking when drag --- .../java/pub/doric/demo/MainActivity.java | 8 +++++++ .../app/src/main/res/layout/activity_main.xml | 15 ++++++++---- .../pub/doric/pullable/CircleImageView.java | 4 ++-- .../pub/doric/pullable/DoricSwipeLayout.java | 23 ++++++++++++------- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Android/app/src/main/java/pub/doric/demo/MainActivity.java b/Android/app/src/main/java/pub/doric/demo/MainActivity.java index 4eaf9ad9..c472cc8c 100644 --- a/Android/app/src/main/java/pub/doric/demo/MainActivity.java +++ b/Android/app/src/main/java/pub/doric/demo/MainActivity.java @@ -34,6 +34,7 @@ import java.util.List; import pub.doric.DoricActivity; import pub.doric.devkit.ui.DemoDebugActivity; +import pub.doric.pullable.DoricSwipeLayout; import pub.doric.utils.DoricUtils; public class MainActivity extends AppCompatActivity { @@ -43,6 +44,13 @@ public class MainActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + final DoricSwipeLayout swipeLayout = findViewById(R.id.swipe_layout); + swipeLayout.setOnRefreshListener(new DoricSwipeLayout.OnRefreshListener() { + @Override + public void onRefresh() { + swipeLayout.setRefreshing(false); + } + }); RecyclerView recyclerView = findViewById(R.id.root); recyclerView.setLayoutManager(new LinearLayoutManager(this)); try { diff --git a/Android/app/src/main/res/layout/activity_main.xml b/Android/app/src/main/res/layout/activity_main.xml index 4abb9bc3..95619501 100644 --- a/Android/app/src/main/res/layout/activity_main.xml +++ b/Android/app/src/main/res/layout/activity_main.xml @@ -1,8 +1,13 @@ - - \ No newline at end of file + android:layout_height="match_parent"> + + + \ No newline at end of file diff --git a/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java b/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java index 70f663dd..b003051b 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java +++ b/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java @@ -26,8 +26,8 @@ import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.view.View; import android.view.animation.Animation; -import android.widget.ImageView; +import androidx.appcompat.widget.AppCompatImageView; import androidx.core.content.ContextCompat; import androidx.core.view.ViewCompat; @@ -36,7 +36,7 @@ import androidx.core.view.ViewCompat; * called before the animation is actually complete and support shadows on older * platforms. */ -class CircleImageView extends ImageView { +class CircleImageView extends AppCompatImageView { private static final int KEY_SHADOW_COLOR = 0x1E000000; private static final int FILL_SHADOW_COLOR = 0x3D000000; diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java index d128dc6e..3a1d9245 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java @@ -51,7 +51,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent @VisibleForTesting static final int CIRCLE_DIAMETER_LARGE = 56; - private static final String LOG_TAG = androidx.swiperefreshlayout.widget.SwipeRefreshLayout.class.getSimpleName(); + private static final String LOG_TAG = DoricSwipeLayout.class.getSimpleName(); private static final int MAX_ALPHA = 255; private static final int STARTING_PROGRESS_ALPHA = (int) (.3f * MAX_ALPHA); @@ -587,16 +587,19 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent if (mTarget == null) { return; } + + int circleWidth = mCircleView.getMeasuredWidth(); + int circleHeight = mCircleView.getMeasuredHeight(); + + mCircleView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop, + (width / 2 + circleWidth / 2), mCurrentTargetOffsetTop + circleHeight); + final View child = mTarget; final int childLeft = getPaddingLeft(); - final int childTop = getPaddingTop(); + final int childTop = getPaddingTop() + mCircleView.getBottom(); final int childWidth = width - getPaddingLeft() - getPaddingRight(); final int childHeight = height - getPaddingTop() - getPaddingBottom(); child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); - int circleWidth = mCircleView.getMeasuredWidth(); - int circleHeight = mCircleView.getMeasuredHeight(); - mCircleView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop, - (width / 2 + circleWidth / 2), mCurrentTargetOffsetTop + circleHeight); } @Override @@ -756,8 +759,10 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent consumed[1] = dy - (int) mTotalUnconsumed; mTotalUnconsumed = 0; } else { - mTotalUnconsumed -= dy; - consumed[1] = dy; + if (dy > 3) { + mTotalUnconsumed -= dy; + consumed[1] = dy; + } } moveSpinner(mTotalUnconsumed); } @@ -1179,4 +1184,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent */ boolean canChildScrollUp(@NonNull DoricSwipeLayout parent, @Nullable View child); } + + } \ No newline at end of file From 9c6802dccfcd3b5821ca0794fd79f49cafdd75ae Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Mon, 25 Nov 2019 19:28:42 +0800 Subject: [PATCH 03/35] feat:fix SwipeLayout --- .../java/pub/doric/demo/MainActivity.java | 5 + .../pub/doric/pullable/DoricRefreshView.java | 22 ++ .../pub/doric/pullable/DoricSwipeLayout.java | 272 ++++-------------- 3 files changed, 84 insertions(+), 215 deletions(-) diff --git a/Android/app/src/main/java/pub/doric/demo/MainActivity.java b/Android/app/src/main/java/pub/doric/demo/MainActivity.java index c472cc8c..7d3ece4f 100644 --- a/Android/app/src/main/java/pub/doric/demo/MainActivity.java +++ b/Android/app/src/main/java/pub/doric/demo/MainActivity.java @@ -16,6 +16,7 @@ package pub.doric.demo; import android.content.Intent; +import android.graphics.Color; import android.os.Bundle; import android.util.TypedValue; import android.view.Gravity; @@ -51,7 +52,11 @@ public class MainActivity extends AppCompatActivity { swipeLayout.setRefreshing(false); } }); + swipeLayout.setBackgroundColor(Color.YELLOW); + swipeLayout.getRefreshView().setBackgroundColor(Color.RED); + swipeLayout.setPullDownHeight(100); RecyclerView recyclerView = findViewById(R.id.root); + recyclerView.setBackgroundColor(Color.WHITE); recyclerView.setLayoutManager(new LinearLayoutManager(this)); try { String[] demos = getAssets().list("demo"); diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java b/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java index 90e376f2..2d404750 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java @@ -5,6 +5,7 @@ import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; +import android.view.animation.Animation; import android.widget.FrameLayout; import androidx.annotation.AttrRes; @@ -18,6 +19,7 @@ import androidx.annotation.Nullable; */ public class DoricRefreshView extends FrameLayout implements IPullable { private View content; + private Animation.AnimationListener mListener; public DoricRefreshView(@NonNull Context context) { super(context); @@ -77,4 +79,24 @@ public class DoricRefreshView extends FrameLayout implements IPullable { ((IPullable) content).setProgressRotation(rotation); } } + + public void setAnimationListener(Animation.AnimationListener listener) { + mListener = listener; + } + + @Override + protected void onAnimationStart() { + super.onAnimationStart(); + if (mListener != null) { + mListener.onAnimationStart(getAnimation()); + } + } + + @Override + protected void onAnimationEnd() { + super.onAnimationEnd(); + if (mListener != null) { + mListener.onAnimationEnd(getAnimation()); + } + } } \ No newline at end of file diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java index 3a1d9245..f83c3431 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java @@ -15,13 +15,10 @@ import android.view.animation.Transformation; import android.widget.AbsListView; import android.widget.ListView; -import androidx.annotation.ColorInt; -import androidx.annotation.ColorRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.Px; import androidx.annotation.VisibleForTesting; -import androidx.core.content.ContextCompat; import androidx.core.view.NestedScrollingChild; import androidx.core.view.NestedScrollingChildHelper; import androidx.core.view.NestedScrollingParent; @@ -111,7 +108,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent android.R.attr.enabled }; - CircleImageView mCircleView; private int mCircleViewIndex = -1; protected int mFrom; @@ -124,27 +120,20 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent int mCustomSlingshotDistance; - CircularProgressDrawable mProgress; - private Animation mScaleAnimation; private Animation mScaleDownAnimation; - private Animation mAlphaStartAnimation; - - private Animation mAlphaMaxAnimation; - private Animation mScaleDownToStartAnimation; boolean mNotify; - private int mCircleDiameter; - // Whether the client has set a custom starting position; boolean mUsingCustomStart; private OnChildScrollUpCallback mChildScrollUpCallback; + private DoricRefreshView mRefreshView; private AnimationListener mRefreshListener = new AnimationListener() { @Override public void onAnimationStart(Animation animation) { @@ -157,33 +146,30 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent @Override public void onAnimationEnd(Animation animation) { if (mRefreshing) { - // Make sure the progress view is fully visible - mProgress.setAlpha(MAX_ALPHA); - mProgress.start(); + mRefreshView.startAnimation(); if (mNotify) { if (mListener != null) { mListener.onRefresh(); } } - mCurrentTargetOffsetTop = mCircleView.getTop(); + mCurrentTargetOffsetTop = mRefreshView.getTop(); } else { reset(); } } }; + private int mPullDownHeight = 0; void reset() { - mCircleView.clearAnimation(); - mProgress.stop(); - mCircleView.setVisibility(View.GONE); - setColorViewAlpha(MAX_ALPHA); + mRefreshView.stopAnimation(); + mRefreshView.setVisibility(View.GONE); // Return the circle to its start position if (mScale) { setAnimationProgress(0 /* animation complete and view is hidden */); } else { setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop); } - mCurrentTargetOffsetTop = mCircleView.getTop(); + mCurrentTargetOffsetTop = mRefreshView.getTop(); } @Override @@ -200,11 +186,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent reset(); } - private void setColorViewAlpha(int targetAlpha) { - mCircleView.getBackground().setAlpha(targetAlpha); - mProgress.setAlpha(targetAlpha); - } - /** * The refresh indicator starting and resting position is always positioned * near the top of the refreshing content. This position is a consistent @@ -265,7 +246,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent public void setProgressViewEndTarget(boolean scale, int end) { mSpinnerOffsetEnd = end; mScale = scale; - mCircleView.invalidate(); + mRefreshView.invalidate(); } /** @@ -279,27 +260,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent mCustomSlingshotDistance = slingshotDistance; } - /** - * One of DEFAULT, or LARGE. - */ - public void setSize(int size) { - if (size != CircularProgressDrawable.LARGE && size != CircularProgressDrawable.DEFAULT) { - return; - } - final DisplayMetrics metrics = getResources().getDisplayMetrics(); - if (size == CircularProgressDrawable.LARGE) { - mCircleDiameter = (int) (CIRCLE_DIAMETER_LARGE * metrics.density); - } else { - mCircleDiameter = (int) (CIRCLE_DIAMETER * metrics.density); - } - // force the bounds of the progress circle inside the circle view to - // update by setting it to null before updating its size and then - // re-setting it - mCircleView.setImageDrawable(null); - mProgress.setStyle(size); - mCircleView.setImageDrawable(mProgress); - } - /** * Simple constructor to use when creating a SwipeRefreshLayout from code. * @@ -327,7 +287,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR); final DisplayMetrics metrics = getResources().getDisplayMetrics(); - mCircleDiameter = (int) (CIRCLE_DIAMETER * metrics.density); createProgressView(); setChildrenDrawingOrderEnabled(true); @@ -339,7 +298,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent mNestedScrollingChildHelper = new NestedScrollingChildHelper(this); setNestedScrollingEnabled(true); - mOriginalOffsetTop = mCurrentTargetOffsetTop = -mCircleDiameter; moveToStart(1.0f); final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); @@ -347,6 +305,11 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent a.recycle(); } + public void setPullDownHeight(int height) { + mPullDownHeight = height; + mOriginalOffsetTop = mCurrentTargetOffsetTop = -height; + } + @Override protected int getChildDrawingOrder(int childCount, int i) { if (mCircleViewIndex < 0) { @@ -364,12 +327,13 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } private void createProgressView() { - mCircleView = new CircleImageView(getContext(), CIRCLE_BG_LIGHT); - mProgress = new CircularProgressDrawable(getContext()); - mProgress.setStyle(CircularProgressDrawable.DEFAULT); - mCircleView.setImageDrawable(mProgress); - mCircleView.setVisibility(View.GONE); - addView(mCircleView); + mRefreshView = new DoricRefreshView(getContext()); + ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, 0); + addView(mRefreshView, layoutParams); + } + + public DoricRefreshView getRefreshView() { + return mRefreshView; } /** @@ -405,8 +369,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } private void startScaleUpAnimation(AnimationListener listener) { - mCircleView.setVisibility(View.VISIBLE); - mProgress.setAlpha(MAX_ALPHA); + mRefreshView.setVisibility(View.VISIBLE); mScaleAnimation = new Animation() { @Override public void applyTransformation(float interpolatedTime, Transformation t) { @@ -415,10 +378,10 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent }; mScaleAnimation.setDuration(mMediumAnimationDuration); if (listener != null) { - mCircleView.setAnimationListener(listener); + mRefreshView.setAnimationListener(listener); } - mCircleView.clearAnimation(); - mCircleView.startAnimation(mScaleAnimation); + mRefreshView.clearAnimation(); + mRefreshView.startAnimation(mScaleAnimation); } /** @@ -427,8 +390,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent * @param progress */ void setAnimationProgress(float progress) { - mCircleView.setScaleX(progress); - mCircleView.setScaleY(progress); + mRefreshView.setProgressRotation(progress); } private void setRefreshing(boolean refreshing, final boolean notify) { @@ -452,95 +414,9 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } }; mScaleDownAnimation.setDuration(SCALE_DOWN_DURATION); - mCircleView.setAnimationListener(listener); - mCircleView.clearAnimation(); - mCircleView.startAnimation(mScaleDownAnimation); - } - - private void startProgressAlphaStartAnimation() { - mAlphaStartAnimation = startAlphaAnimation(mProgress.getAlpha(), STARTING_PROGRESS_ALPHA); - } - - private void startProgressAlphaMaxAnimation() { - mAlphaMaxAnimation = startAlphaAnimation(mProgress.getAlpha(), MAX_ALPHA); - } - - private Animation startAlphaAnimation(final int startingAlpha, final int endingAlpha) { - Animation alpha = new Animation() { - @Override - public void applyTransformation(float interpolatedTime, Transformation t) { - mProgress.setAlpha( - (int) (startingAlpha + ((endingAlpha - startingAlpha) * interpolatedTime))); - } - }; - alpha.setDuration(ALPHA_ANIMATION_DURATION); - // Clear out the previous animation listeners. - mCircleView.setAnimationListener(null); - mCircleView.clearAnimation(); - mCircleView.startAnimation(alpha); - return alpha; - } - - /** - * @deprecated Use {@link #setProgressBackgroundColorSchemeResource(int)} - */ - @Deprecated - public void setProgressBackgroundColor(int colorRes) { - setProgressBackgroundColorSchemeResource(colorRes); - } - - /** - * Set the background color of the progress spinner disc. - * - * @param colorRes Resource id of the color. - */ - public void setProgressBackgroundColorSchemeResource(@ColorRes int colorRes) { - setProgressBackgroundColorSchemeColor(ContextCompat.getColor(getContext(), colorRes)); - } - - /** - * Set the background color of the progress spinner disc. - * - * @param color - */ - public void setProgressBackgroundColorSchemeColor(@ColorInt int color) { - mCircleView.setBackgroundColor(color); - } - - /** - * @deprecated Use {@link #setColorSchemeResources(int...)} - */ - @Deprecated - public void setColorScheme(@ColorRes int... colors) { - setColorSchemeResources(colors); - } - - /** - * Set the color resources used in the progress animation from color resources. - * The first color will also be the color of the bar that grows in response - * to a user swipe gesture. - * - * @param colorResIds - */ - public void setColorSchemeResources(@ColorRes int... colorResIds) { - final Context context = getContext(); - int[] colorRes = new int[colorResIds.length]; - for (int i = 0; i < colorResIds.length; i++) { - colorRes[i] = ContextCompat.getColor(context, colorResIds[i]); - } - setColorSchemeColors(colorRes); - } - - /** - * Set the colors used in the progress animation. The first - * color will also be the color of the bar that grows in response to a user - * swipe gesture. - * - * @param colors - */ - public void setColorSchemeColors(@ColorInt int... colors) { - ensureTarget(); - mProgress.setColorSchemeColors(colors); + mRefreshView.setAnimationListener(listener); + mRefreshView.clearAnimation(); + mRefreshView.startAnimation(mScaleDownAnimation); } /** @@ -557,7 +433,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent if (mTarget == null) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); - if (!child.equals(mCircleView)) { + if (!child.equals(mRefreshView)) { mTarget = child; break; } @@ -588,15 +464,15 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent return; } - int circleWidth = mCircleView.getMeasuredWidth(); - int circleHeight = mCircleView.getMeasuredHeight(); + int circleWidth = mRefreshView.getMeasuredWidth(); + int circleHeight = mRefreshView.getMeasuredHeight(); - mCircleView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop, + mRefreshView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop, (width / 2 + circleWidth / 2), mCurrentTargetOffsetTop + circleHeight); final View child = mTarget; final int childLeft = getPaddingLeft(); - final int childTop = getPaddingTop() + mCircleView.getBottom(); + final int childTop = getPaddingTop() + mRefreshView.getBottom(); final int childWidth = width - getPaddingLeft() - getPaddingRight(); final int childHeight = height - getPaddingTop() - getPaddingBottom(); child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); @@ -615,28 +491,18 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec( getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY)); - mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY)); + mRefreshView.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(mPullDownHeight, MeasureSpec.EXACTLY)); mCircleViewIndex = -1; // Get the index of the circleview. for (int index = 0; index < getChildCount(); index++) { - if (getChildAt(index) == mCircleView) { + if (getChildAt(index) == mRefreshView) { mCircleViewIndex = index; break; } } } - /** - * Get the diameter of the progress circle that is displayed as part of the - * swipe to refresh layout. - * - * @return Diameter in pixels of the progress circle view. - */ - public int getProgressCircleDiameter() { - return mCircleDiameter; - } - /** * @return Whether it is possible for the child view of this layout to * scroll up. Override this if the child view is a custom view. @@ -680,7 +546,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent switch (action) { case MotionEvent.ACTION_DOWN: - setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop()); + setTargetOffsetTopAndBottom(mOriginalOffsetTop - mRefreshView.getTop()); mActivePointerId = ev.getPointerId(0); mIsBeingDragged = false; @@ -773,7 +639,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent // the circle so it isn't exposed if its blocking content is moved if (mUsingCustomStart && dy > 0 && mTotalUnconsumed == 0 && Math.abs(dy - consumed[1]) > 0) { - mCircleView.setVisibility(View.GONE); + mRefreshView.setVisibility(View.GONE); } // Now let our nested parent consume the leftovers @@ -889,11 +755,9 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } private void moveSpinner(float overscrollTop) { - mProgress.setArrowEnabled(true); float originalDragPercent = overscrollTop / mTotalDragDistance; float dragPercent = Math.min(1f, Math.abs(originalDragPercent)); - float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3; float extraOS = Math.abs(overscrollTop) - mTotalDragDistance; float slingshotDist = mCustomSlingshotDistance > 0 ? mCustomSlingshotDistance @@ -908,35 +772,17 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent int targetY = mOriginalOffsetTop + (int) ((slingshotDist * dragPercent) + extraMove); // where 1.0f is a full circle - if (mCircleView.getVisibility() != View.VISIBLE) { - mCircleView.setVisibility(View.VISIBLE); + if (mRefreshView.getVisibility() != View.VISIBLE) { + mRefreshView.setVisibility(View.VISIBLE); } if (!mScale) { - mCircleView.setScaleX(1f); - mCircleView.setScaleY(1f); + mRefreshView.setScaleX(1f); + mRefreshView.setScaleY(1f); } if (mScale) { setAnimationProgress(Math.min(1f, overscrollTop / mTotalDragDistance)); } - if (overscrollTop < mTotalDragDistance) { - if (mProgress.getAlpha() > STARTING_PROGRESS_ALPHA - && !isAnimationRunning(mAlphaStartAnimation)) { - // Animate the alpha - startProgressAlphaStartAnimation(); - } - } else { - if (mProgress.getAlpha() < MAX_ALPHA && !isAnimationRunning(mAlphaMaxAnimation)) { - // Animate the alpha - startProgressAlphaMaxAnimation(); - } - } - float strokeStart = adjustedPercent * .8f; - mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart)); - mProgress.setArrowScale(Math.min(1f, adjustedPercent)); - - float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f; - mProgress.setProgressRotation(rotation); setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop); } @@ -946,7 +792,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } else { // cancel refresh mRefreshing = false; - mProgress.setStartEndTrim(0f, 0f); Animation.AnimationListener listener = null; if (!mScale) { listener = new Animation.AnimationListener() { @@ -969,7 +814,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent }; } animateOffsetToStartPosition(mCurrentTargetOffsetTop, listener); - mProgress.setArrowEnabled(false); } } @@ -1057,7 +901,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent if (yDiff > mTouchSlop && !mIsBeingDragged) { mInitialMotionY = mInitialDownY + mTouchSlop; mIsBeingDragged = true; - mProgress.setAlpha(STARTING_PROGRESS_ALPHA); } } @@ -1067,10 +910,10 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent mAnimateToCorrectPosition.setDuration(ANIMATE_TO_TRIGGER_DURATION); mAnimateToCorrectPosition.setInterpolator(mDecelerateInterpolator); if (listener != null) { - mCircleView.setAnimationListener(listener); + mRefreshView.setAnimationListener(listener); } - mCircleView.clearAnimation(); - mCircleView.startAnimation(mAnimateToCorrectPosition); + mRefreshView.clearAnimation(); + mRefreshView.startAnimation(mAnimateToCorrectPosition); } private void animateOffsetToStartPosition(int from, AnimationListener listener) { @@ -1083,10 +926,10 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent mAnimateToStartPosition.setDuration(ANIMATE_TO_START_DURATION); mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator); if (listener != null) { - mCircleView.setAnimationListener(listener); + mRefreshView.setAnimationListener(listener); } - mCircleView.clearAnimation(); - mCircleView.startAnimation(mAnimateToStartPosition); + mRefreshView.clearAnimation(); + mRefreshView.startAnimation(mAnimateToStartPosition); } } @@ -1101,16 +944,15 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent endTarget = mSpinnerOffsetEnd; } targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime)); - int offset = targetTop - mCircleView.getTop(); + int offset = targetTop - mRefreshView.getTop(); setTargetOffsetTopAndBottom(offset); - mProgress.setArrowScale(1 - interpolatedTime); } }; void moveToStart(float interpolatedTime) { int targetTop = 0; targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime)); - int offset = targetTop - mCircleView.getTop(); + int offset = targetTop - mRefreshView.getTop(); setTargetOffsetTopAndBottom(offset); } @@ -1124,7 +966,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent private void startScaleDownReturnToStartAnimation(int from, Animation.AnimationListener listener) { mFrom = from; - mStartingScale = mCircleView.getScaleX(); + mStartingScale = mRefreshView.getScaleX(); mScaleDownToStartAnimation = new Animation() { @Override public void applyTransformation(float interpolatedTime, Transformation t) { @@ -1135,16 +977,16 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent }; mScaleDownToStartAnimation.setDuration(SCALE_DOWN_DURATION); if (listener != null) { - mCircleView.setAnimationListener(listener); + mRefreshView.setAnimationListener(listener); } - mCircleView.clearAnimation(); - mCircleView.startAnimation(mScaleDownToStartAnimation); + mRefreshView.clearAnimation(); + mRefreshView.startAnimation(mScaleDownToStartAnimation); } void setTargetOffsetTopAndBottom(int offset) { - mCircleView.bringToFront(); - ViewCompat.offsetTopAndBottom(mCircleView, offset); - mCurrentTargetOffsetTop = mCircleView.getTop(); + mRefreshView.bringToFront(); + ViewCompat.offsetTopAndBottom(mRefreshView, offset); + mCurrentTargetOffsetTop = mRefreshView.getTop(); } private void onSecondaryPointerUp(MotionEvent ev) { From 055699d2219a6731b6001c459d00af8ca97f0cec Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Mon, 25 Nov 2019 20:35:11 +0800 Subject: [PATCH 04/35] feat:SwipeLayout --- .../java/pub/doric/demo/MainActivity.java | 2 +- .../pub/doric/pullable/CircleImageView.java | 159 ------------------ .../pub/doric/pullable/DoricSwipeLayout.java | 144 ++++++---------- 3 files changed, 51 insertions(+), 254 deletions(-) delete mode 100644 Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java diff --git a/Android/app/src/main/java/pub/doric/demo/MainActivity.java b/Android/app/src/main/java/pub/doric/demo/MainActivity.java index 7d3ece4f..eb9886f9 100644 --- a/Android/app/src/main/java/pub/doric/demo/MainActivity.java +++ b/Android/app/src/main/java/pub/doric/demo/MainActivity.java @@ -54,7 +54,7 @@ public class MainActivity extends AppCompatActivity { }); swipeLayout.setBackgroundColor(Color.YELLOW); swipeLayout.getRefreshView().setBackgroundColor(Color.RED); - swipeLayout.setPullDownHeight(100); + swipeLayout.setPullDownHeight(300); RecyclerView recyclerView = findViewById(R.id.root); recyclerView.setBackgroundColor(Color.WHITE); recyclerView.setLayoutManager(new LinearLayoutManager(this)); diff --git a/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java b/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java deleted file mode 100644 index b003051b..00000000 --- a/Android/doric/src/main/java/pub/doric/pullable/CircleImageView.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * 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. - */ - -package pub.doric.pullable; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.RadialGradient; -import android.graphics.Shader; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.shapes.OvalShape; -import android.view.View; -import android.view.animation.Animation; - -import androidx.appcompat.widget.AppCompatImageView; -import androidx.core.content.ContextCompat; -import androidx.core.view.ViewCompat; - -/** - * Private class created to work around issues with AnimationListeners being - * called before the animation is actually complete and support shadows on older - * platforms. - */ -class CircleImageView extends AppCompatImageView { - - private static final int KEY_SHADOW_COLOR = 0x1E000000; - private static final int FILL_SHADOW_COLOR = 0x3D000000; - // PX - private static final float X_OFFSET = 0f; - private static final float Y_OFFSET = 1.75f; - private static final float SHADOW_RADIUS = 3.5f; - private static final int SHADOW_ELEVATION = 4; - - private Animation.AnimationListener mListener; - int mShadowRadius; - - CircleImageView(Context context, int color) { - super(context); - final float density = getContext().getResources().getDisplayMetrics().density; - final int shadowYOffset = (int) (density * Y_OFFSET); - final int shadowXOffset = (int) (density * X_OFFSET); - - mShadowRadius = (int) (density * SHADOW_RADIUS); - - ShapeDrawable circle; - if (elevationSupported()) { - circle = new ShapeDrawable(new OvalShape()); - ViewCompat.setElevation(this, SHADOW_ELEVATION * density); - } else { - OvalShape oval = new OvalShadow(mShadowRadius); - circle = new ShapeDrawable(oval); - setLayerType(View.LAYER_TYPE_SOFTWARE, circle.getPaint()); - circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset, - KEY_SHADOW_COLOR); - final int padding = mShadowRadius; - // set padding so the inner image sits correctly within the shadow. - setPadding(padding, padding, padding, padding); - } - circle.getPaint().setColor(color); - ViewCompat.setBackground(this, circle); - } - - private boolean elevationSupported() { - return android.os.Build.VERSION.SDK_INT >= 21; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (!elevationSupported()) { - setMeasuredDimension(getMeasuredWidth() + mShadowRadius * 2, getMeasuredHeight() - + mShadowRadius * 2); - } - } - - public void setAnimationListener(Animation.AnimationListener listener) { - mListener = listener; - } - - @Override - public void onAnimationStart() { - super.onAnimationStart(); - if (mListener != null) { - mListener.onAnimationStart(getAnimation()); - } - } - - @Override - public void onAnimationEnd() { - super.onAnimationEnd(); - if (mListener != null) { - mListener.onAnimationEnd(getAnimation()); - } - } - - /** - * Update the background color of the circle image view. - * - * @param colorRes Id of a color resource. - */ - public void setBackgroundColorRes(int colorRes) { - setBackgroundColor(ContextCompat.getColor(getContext(), colorRes)); - } - - @Override - public void setBackgroundColor(int color) { - if (getBackground() instanceof ShapeDrawable) { - ((ShapeDrawable) getBackground()).getPaint().setColor(color); - } - } - - private class OvalShadow extends OvalShape { - private RadialGradient mRadialGradient; - private Paint mShadowPaint; - - OvalShadow(int shadowRadius) { - super(); - mShadowPaint = new Paint(); - mShadowRadius = shadowRadius; - updateRadialGradient((int) rect().width()); - } - - @Override - protected void onResize(float width, float height) { - super.onResize(width, height); - updateRadialGradient((int) width); - } - - @Override - public void draw(Canvas canvas, Paint paint) { - final int viewWidth = CircleImageView.this.getWidth(); - final int viewHeight = CircleImageView.this.getHeight(); - canvas.drawCircle(viewWidth / 2, viewHeight / 2, viewWidth / 2, mShadowPaint); - canvas.drawCircle(viewWidth / 2, viewHeight / 2, viewWidth / 2 - mShadowRadius, paint); - } - - private void updateRadialGradient(int diameter) { - mRadialGradient = new RadialGradient(diameter / 2, diameter / 2, - mShadowRadius, new int[]{FILL_SHADOW_COLOR, Color.TRANSPARENT}, - null, Shader.TileMode.CLAMP); - mShadowPaint.setShader(mRadialGradient); - } - } -} diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java index f83c3431..b0dfd6be 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java @@ -1,5 +1,7 @@ package pub.doric.pullable; +import android.animation.Animator; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; @@ -17,7 +19,6 @@ import android.widget.ListView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.Px; import androidx.annotation.VisibleForTesting; import androidx.core.view.NestedScrollingChild; import androidx.core.view.NestedScrollingChildHelper; @@ -69,8 +70,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent private static final int ANIMATE_TO_START_DURATION = 200; - // Default background for the progress spinner - private static final int CIRCLE_BG_LIGHT = 0xFFFAFAFA; // Default offset in dips from the top of the view to where the progress spinner should stop private static final int DEFAULT_CIRCLE_TARGET = 64; @@ -159,17 +158,55 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } }; private int mPullDownHeight = 0; + private ValueAnimator headerViewAnimator; void reset() { - mRefreshView.stopAnimation(); - mRefreshView.setVisibility(View.GONE); - // Return the circle to its start position - if (mScale) { - setAnimationProgress(0 /* animation complete and view is hidden */); - } else { - setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop); + if (headerViewAnimator != null && headerViewAnimator.isRunning()) { + headerViewAnimator.cancel(); } - mCurrentTargetOffsetTop = mRefreshView.getTop(); + headerViewAnimator = ValueAnimator.ofInt(mRefreshView.getBottom(), 0); + headerViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mCurrentTargetOffsetTop = (int) animation.getAnimatedValue() + - mRefreshView.getMeasuredHeight(); + mRefreshView.requestLayout(); + } + }); + headerViewAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + mRefreshView.stopAnimation(); + mRefreshView.setVisibility(View.GONE); + // Return the circle to its start position + + if (mScale) { + setAnimationProgress(0 /* animation complete and view is hidden */); + } else { + setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop); + } + mCurrentTargetOffsetTop = mRefreshView.getTop(); + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + headerViewAnimator.setDuration(SCALE_DOWN_DURATION); + headerViewAnimator.start(); + + } @Override @@ -186,80 +223,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent reset(); } - /** - * The refresh indicator starting and resting position is always positioned - * near the top of the refreshing content. This position is a consistent - * location, but can be adjusted in either direction based on whether or not - * there is a toolbar or actionbar present. - *

- * Note: Calling this will reset the position of the refresh indicator to - * start. - *

- * - * @param scale Set to true if there is no view at a higher z-order than where the progress - * spinner is set to appear. Setting it to true will cause indicator to be scaled - * up rather than clipped. - * @param start The offset in pixels from the top of this view at which the - * progress spinner should appear. - * @param end The offset in pixels from the top of this view at which the - * progress spinner should come to rest after a successful swipe - * gesture. - */ - public void setProgressViewOffset(boolean scale, int start, int end) { - mScale = scale; - mOriginalOffsetTop = start; - mSpinnerOffsetEnd = end; - mUsingCustomStart = true; - reset(); - mRefreshing = false; - } - - /** - * @return The offset in pixels from the top of this view at which the progress spinner should - * appear. - */ - public int getProgressViewStartOffset() { - return mOriginalOffsetTop; - } - - /** - * @return The offset in pixels from the top of this view at which the progress spinner should - * come to rest after a successful swipe gesture. - */ - public int getProgressViewEndOffset() { - return mSpinnerOffsetEnd; - } - - /** - * The refresh indicator resting position is always positioned near the top - * of the refreshing content. This position is a consistent location, but - * can be adjusted in either direction based on whether or not there is a - * toolbar or actionbar present. - * - * @param scale Set to true if there is no view at a higher z-order than where the progress - * spinner is set to appear. Setting it to true will cause indicator to be scaled - * up rather than clipped. - * @param end The offset in pixels from the top of this view at which the - * progress spinner should come to rest after a successful swipe - * gesture. - */ - public void setProgressViewEndTarget(boolean scale, int end) { - mSpinnerOffsetEnd = end; - mScale = scale; - mRefreshView.invalidate(); - } - - /** - * Sets a custom slingshot distance. - * - * @param slingshotDistance The distance in pixels that the refresh indicator can be pulled - * beyond its resting position. Use - * {@link #DEFAULT_SLINGSHOT_DISTANCE} to reset to the default value. - */ - public void setSlingshotDistance(@Px int slingshotDistance) { - mCustomSlingshotDistance = slingshotDistance; - } - /** * Simple constructor to use when creating a SwipeRefreshLayout from code. * @@ -308,6 +271,8 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent public void setPullDownHeight(int height) { mPullDownHeight = height; mOriginalOffsetTop = mCurrentTargetOffsetTop = -height; + mSpinnerOffsetEnd = height; + mTotalDragDistance = height; } @Override @@ -441,15 +406,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } } - /** - * Set the distance to trigger a sync in dips - * - * @param distance - */ - public void setDistanceToTriggerSync(int distance) { - mTotalDragDistance = distance; - } - @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { final int width = getMeasuredWidth(); From c766e57c830356c8ce47f1fc9d21d5f9390d46f8 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Mon, 25 Nov 2019 20:50:08 +0800 Subject: [PATCH 05/35] feat:optimize ProgressRotation --- .../pub/doric/pullable/DoricSwipeLayout.java | 90 ++++++------------- 1 file changed, 27 insertions(+), 63 deletions(-) diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java index b0dfd6be..ef845880 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java @@ -96,8 +96,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent private float mInitialDownY; private boolean mIsBeingDragged; private int mActivePointerId = INVALID_POINTER; - // Whether this item is scaled up rather than clipped - boolean mScale; // Target is returning to its start offset because it was cancelled or a // refresh was triggered. @@ -185,11 +183,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent mRefreshView.setVisibility(View.GONE); // Return the circle to its start position - if (mScale) { - setAnimationProgress(0 /* animation complete and view is hidden */); - } else { - setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop); - } + setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop); mCurrentTargetOffsetTop = mRefreshView.getTop(); } @@ -355,7 +349,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent * @param progress */ void setAnimationProgress(float progress) { - mRefreshView.setProgressRotation(progress); + } private void setRefreshing(boolean refreshing, final boolean notify) { @@ -731,14 +725,9 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent if (mRefreshView.getVisibility() != View.VISIBLE) { mRefreshView.setVisibility(View.VISIBLE); } - if (!mScale) { - mRefreshView.setScaleX(1f); - mRefreshView.setScaleY(1f); - } + mRefreshView.setScaleX(1f); + mRefreshView.setScaleY(1f); - if (mScale) { - setAnimationProgress(Math.min(1f, overscrollTop / mTotalDragDistance)); - } setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop); } @@ -749,26 +738,22 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent // cancel refresh mRefreshing = false; Animation.AnimationListener listener = null; - if (!mScale) { - listener = new Animation.AnimationListener() { + listener = new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - } + @Override + public void onAnimationStart(Animation animation) { + } - @Override - public void onAnimationEnd(Animation animation) { - if (!mScale) { - startScaleDownAnimation(null); - } - } + @Override + public void onAnimationEnd(Animation animation) { + startScaleDownAnimation(null); + } - @Override - public void onAnimationRepeat(Animation animation) { - } + @Override + public void onAnimationRepeat(Animation animation) { + } - }; - } + }; animateOffsetToStartPosition(mCurrentTargetOffsetTop, listener); } } @@ -873,20 +858,15 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } private void animateOffsetToStartPosition(int from, AnimationListener listener) { - if (mScale) { - // Scale the item back down - startScaleDownReturnToStartAnimation(from, listener); - } else { - mFrom = from; - mAnimateToStartPosition.reset(); - mAnimateToStartPosition.setDuration(ANIMATE_TO_START_DURATION); - mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator); - if (listener != null) { - mRefreshView.setAnimationListener(listener); - } - mRefreshView.clearAnimation(); - mRefreshView.startAnimation(mAnimateToStartPosition); + mFrom = from; + mAnimateToStartPosition.reset(); + mAnimateToStartPosition.setDuration(ANIMATE_TO_START_DURATION); + mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator); + if (listener != null) { + mRefreshView.setAnimationListener(listener); } + mRefreshView.clearAnimation(); + mRefreshView.startAnimation(mAnimateToStartPosition); } private final Animation mAnimateToCorrectPosition = new Animation() { @@ -919,30 +899,14 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent } }; - private void startScaleDownReturnToStartAnimation(int from, - Animation.AnimationListener listener) { - mFrom = from; - mStartingScale = mRefreshView.getScaleX(); - mScaleDownToStartAnimation = new Animation() { - @Override - public void applyTransformation(float interpolatedTime, Transformation t) { - float targetScale = (mStartingScale + (-mStartingScale * interpolatedTime)); - setAnimationProgress(targetScale); - moveToStart(interpolatedTime); - } - }; - mScaleDownToStartAnimation.setDuration(SCALE_DOWN_DURATION); - if (listener != null) { - mRefreshView.setAnimationListener(listener); - } - mRefreshView.clearAnimation(); - mRefreshView.startAnimation(mScaleDownToStartAnimation); - } void setTargetOffsetTopAndBottom(int offset) { mRefreshView.bringToFront(); ViewCompat.offsetTopAndBottom(mRefreshView, offset); mCurrentTargetOffsetTop = mRefreshView.getTop(); + if (mRefreshView.getMeasuredHeight() > 0) { + mRefreshView.setProgressRotation((float) mRefreshView.getBottom() / (float) mRefreshView.getMeasuredHeight()); + } } private void onSecondaryPointerUp(MotionEvent ev) { From 362ec833c9840bb02f99048a5911790cffe6e40b Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 10:31:17 +0800 Subject: [PATCH 06/35] feat:add RefreshableDemo for Android --- .../java/pub/doric/demo/MainActivity.java | 6 +- .../main/java/pub/doric/DoricRegistry.java | 2 + .../pub/doric/pullable/DoricSwipeLayout.java | 14 +- .../pub/doric/pullable/RefreshableNode.java | 165 ++++++++++++++++++ demo/index.ts | 1 + demo/src/RefreshableDemo.ts | 72 ++++++++ js-framework/index.ts | 1 + js-framework/src/ui/refreshable.ts | 60 +++++++ js-framework/src/ui/view.ts | 2 +- 9 files changed, 318 insertions(+), 5 deletions(-) create mode 100644 Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java create mode 100644 demo/src/RefreshableDemo.ts create mode 100644 js-framework/src/ui/refreshable.ts diff --git a/Android/app/src/main/java/pub/doric/demo/MainActivity.java b/Android/app/src/main/java/pub/doric/demo/MainActivity.java index eb9886f9..ad02e812 100644 --- a/Android/app/src/main/java/pub/doric/demo/MainActivity.java +++ b/Android/app/src/main/java/pub/doric/demo/MainActivity.java @@ -29,6 +29,8 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import org.w3c.dom.Text; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -54,7 +56,9 @@ public class MainActivity extends AppCompatActivity { }); swipeLayout.setBackgroundColor(Color.YELLOW); swipeLayout.getRefreshView().setBackgroundColor(Color.RED); - swipeLayout.setPullDownHeight(300); + TextView textView = new TextView(this); + textView.setText("This is header"); + swipeLayout.getRefreshView().setContent(textView); RecyclerView recyclerView = findViewById(R.id.root); recyclerView.setBackgroundColor(Color.WHITE); recyclerView.setLayoutManager(new LinearLayoutManager(this)); diff --git a/Android/doric/src/main/java/pub/doric/DoricRegistry.java b/Android/doric/src/main/java/pub/doric/DoricRegistry.java index 12722dc4..c41c1b5a 100644 --- a/Android/doric/src/main/java/pub/doric/DoricRegistry.java +++ b/Android/doric/src/main/java/pub/doric/DoricRegistry.java @@ -25,6 +25,7 @@ import pub.doric.plugin.NavigatorPlugin; import pub.doric.plugin.NetworkPlugin; import pub.doric.plugin.ShaderPlugin; import pub.doric.plugin.StoragePlugin; +import pub.doric.pullable.RefreshableNode; import pub.doric.shader.HLayoutNode; import pub.doric.shader.ImageNode; import pub.doric.shader.ScrollerNode; @@ -96,6 +97,7 @@ public class DoricRegistry { this.registerViewNode(ScrollerNode.class); this.registerViewNode(SliderNode.class); this.registerViewNode(SlideItemNode.class); + this.registerViewNode(RefreshableNode.class); initRegistry(this); } diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java index ef845880..a83ca478 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java @@ -287,7 +287,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent private void createProgressView() { mRefreshView = new DoricRefreshView(getContext()); - ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, 0); + ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); addView(mRefreshView, layoutParams); } @@ -441,8 +441,16 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec( getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY)); - mRefreshView.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(mPullDownHeight, MeasureSpec.EXACTLY)); + mRefreshView.measure( + MeasureSpec.makeMeasureSpec( + getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), + MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec( + (getMeasuredHeight() - getPaddingTop() - getPaddingBottom()) / 3, + MeasureSpec.UNSPECIFIED)); + if (mPullDownHeight != mRefreshView.getMeasuredHeight()) { + setPullDownHeight(mRefreshView.getMeasuredHeight()); + } mCircleViewIndex = -1; // Get the index of the circleview. for (int index = 0; index < getChildCount(); index++) { diff --git a/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java b/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java new file mode 100644 index 00000000..37fbb31a --- /dev/null +++ b/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java @@ -0,0 +1,165 @@ +package pub.doric.pullable; + +import com.github.pengfeizhou.jscore.JSObject; +import com.github.pengfeizhou.jscore.JSValue; +import com.github.pengfeizhou.jscore.JavaValue; + +import pub.doric.DoricContext; +import pub.doric.extension.bridge.DoricMethod; +import pub.doric.extension.bridge.DoricPlugin; +import pub.doric.extension.bridge.DoricPromise; +import pub.doric.shader.SuperNode; +import pub.doric.shader.ViewNode; + +/** + * @Description: pub.doric.pullable + * @Author: pengfei.zhou + * @CreateDate: 2019-11-26 + */ +@DoricPlugin(name = "Refreshable") +public class RefreshableNode extends SuperNode { + + private String mContentViewId; + private ViewNode mContentNode; + + private String mHeaderViewId; + private ViewNode mHeaderNode; + + public RefreshableNode(DoricContext doricContext) { + super(doricContext); + } + + + @Override + protected DoricSwipeLayout build() { + return new DoricSwipeLayout(getContext()); + } + + @Override + protected void blend(DoricSwipeLayout view, String name, JSValue prop) { + if ("content".equals(name)) { + mContentViewId = prop.asString().value(); + } else if ("header".equals(name)) { + mHeaderViewId = prop.asString().value(); + } else { + super.blend(view, name, prop); + } + } + + @Override + public void blend(JSObject jsObject) { + super.blend(jsObject); + blendContentNode(); + blendHeadNode(); + } + + + private void blendContentNode() { + JSObject contentModel = getSubModel(mContentViewId); + if (contentModel == null) { + return; + } + String viewId = contentModel.getProperty("id").asString().value(); + String type = contentModel.getProperty("type").asString().value(); + JSObject props = contentModel.getProperty("props").asObject(); + if (mContentNode != null) { + if (mContentNode.getId().equals(viewId)) { + //skip + } else { + if (mReusable && type.equals(mContentNode.getType())) { + mContentNode.setId(viewId); + mContentNode.blend(props); + } else { + mView.removeAllViews(); + mContentNode = ViewNode.create(getDoricContext(), type); + mContentNode.setId(viewId); + mContentNode.init(this); + mContentNode.blend(props); + mView.addView(mContentNode.getDoricLayer()); + } + } + } else { + mContentNode = ViewNode.create(getDoricContext(), type); + mContentNode.setId(viewId); + mContentNode.init(this); + mContentNode.blend(props); + mView.addView(mContentNode.getDoricLayer()); + } + } + + private void blendHeadNode() { + JSObject headerModel = getSubModel(mHeaderViewId); + if (headerModel == null) { + return; + } + String viewId = headerModel.getProperty("id").asString().value(); + String type = headerModel.getProperty("type").asString().value(); + JSObject props = headerModel.getProperty("props").asObject(); + if (mHeaderNode != null) { + if (mHeaderNode.getId().equals(viewId)) { + //skip + } else { + if (mReusable && type.equals(mHeaderNode.getType())) { + mHeaderNode.setId(viewId); + mHeaderNode.blend(props); + } else { + mHeaderNode = ViewNode.create(getDoricContext(), type); + mHeaderNode.setId(viewId); + mHeaderNode.init(this); + mHeaderNode.blend(props); + mView.getRefreshView().setContent(mHeaderNode.getDoricLayer()); + } + } + } else { + mHeaderNode = ViewNode.create(getDoricContext(), type); + mHeaderNode.setId(viewId); + mHeaderNode.init(this); + mHeaderNode.blend(props); + mView.getRefreshView().setContent(mHeaderNode.getDoricLayer()); + } + } + + @Override + public ViewNode getSubNodeById(String id) { + if (id.equals(mContentViewId)) { + return mContentNode; + } + if (id.equals(mHeaderViewId)) { + return mHeaderNode; + } + return null; + } + + @Override + protected void blendSubNode(JSObject subProperties) { + String viewId = subProperties.getProperty("id").asString().value(); + ViewNode node = getSubNodeById(viewId); + if (node != null) { + node.blend(subProperties.getProperty("props").asObject()); + } + } + + @DoricMethod + public void setRefreshable(JSValue jsValue, DoricPromise doricPromise) { + boolean refreshable = jsValue.asBoolean().value(); + this.mView.setEnabled(refreshable); + doricPromise.resolve(); + } + + @DoricMethod + public void setRefreshing(JSValue jsValue, DoricPromise doricPromise) { + boolean refreshing = jsValue.asBoolean().value(); + this.mView.setRefreshing(refreshing); + doricPromise.resolve(); + } + + @DoricMethod + public void isRefreshable(DoricPromise doricPromise) { + doricPromise.resolve(new JavaValue(this.mView.isEnabled())); + } + + @DoricMethod + public void isRefreshing(DoricPromise doricPromise) { + doricPromise.resolve(new JavaValue(this.mView.isRefreshing())); + } +} diff --git a/demo/index.ts b/demo/index.ts index 6d413654..7b1bac66 100644 --- a/demo/index.ts +++ b/demo/index.ts @@ -12,4 +12,5 @@ export default [ 'src/StorageDemo', 'src/NavigatorDemo', 'src/NavbarDemo', + 'src/RefreshableDemo', ] \ No newline at end of file diff --git a/demo/src/RefreshableDemo.ts b/demo/src/RefreshableDemo.ts new file mode 100644 index 00000000..24d83750 --- /dev/null +++ b/demo/src/RefreshableDemo.ts @@ -0,0 +1,72 @@ +import { refreshable, Group, Panel, navbar, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text, scroller, layoutConfig, image, IView, IVLayout, ScaleType, modal, IText, network, navigator } from "doric"; +import { title, label, colors } from "./utils"; + +@Entry +class RefreshableDemo extends Panel { + build(rootView: Group): void { + let refreshView = refreshable({ + layoutConfig: layoutConfig().atmost(), + header: text({ + text: "This is Header", + width: 100, + height: 100, + layoutConfig: layoutConfig().exactly(), + }), + content: scroller(vlayout([ + title("Refreshable Demo"), + label('start Refresh').apply({ + width: 300, + height: 50, + bgColor: colors[0], + textSize: 30, + textColor: Color.WHITE, + layoutConfig: layoutConfig().exactly(), + onClick: () => { + refreshView.setRefreshing(context, true) + } + } as IText), + label('stop Refresh').apply({ + width: 300, + height: 50, + bgColor: colors[0], + textSize: 30, + textColor: Color.WHITE, + layoutConfig: layoutConfig().exactly(), + onClick: () => { + refreshView.setRefreshing(context, false) + } + } as IText), + + label('Enable Refresh').apply({ + width: 300, + height: 50, + bgColor: colors[0], + textSize: 30, + textColor: Color.WHITE, + layoutConfig: layoutConfig().exactly(), + onClick: () => { + refreshView.setRefreshable(context, true) + } + } as IText), + + label('Disable Refresh').apply({ + width: 300, + height: 50, + bgColor: colors[0], + textSize: 30, + textColor: Color.WHITE, + layoutConfig: layoutConfig().exactly(), + onClick: () => { + refreshView.setRefreshable(context, false) + } + } as IText), + ]).apply({ + layoutConfig: layoutConfig().atmost().h(LayoutSpec.WRAP_CONTENT), + gravity: gravity().center(), + space: 10, + } as IVLayout)).apply({ + layoutConfig: layoutConfig().atmost(), + }) + }).in(rootView) + } +} \ No newline at end of file diff --git a/js-framework/index.ts b/js-framework/index.ts index 8a5de55b..6fa48cae 100644 --- a/js-framework/index.ts +++ b/js-framework/index.ts @@ -21,6 +21,7 @@ export * from "./src/ui/scroller" export * from "./src/ui/widgets" export * from "./src/ui/panel" export * from "./src/ui/declarative" +export * from "./src/ui/refreshable" export * from "./src/util/color" export * from './src/util/log' export * from './src/util/types' diff --git a/js-framework/src/ui/refreshable.ts b/js-framework/src/ui/refreshable.ts new file mode 100644 index 00000000..f1ca4704 --- /dev/null +++ b/js-framework/src/ui/refreshable.ts @@ -0,0 +1,60 @@ +import { View, Property, Superview, IView } from "./view"; +import { List } from "./list"; +import { Scroller } from "./scroller"; +import { BridgeContext } from "../runtime/global"; +import { layoutConfig } from "./declarative"; + +export interface IRefreshable extends IView { + content: List | Scroller + header?: View + onRefresh?: () => void +} + +export class Refreshable extends Superview implements IRefreshable { + + content!: List | Scroller + + header?: View + + @Property + onRefresh?: () => void + + allSubviews() { + const ret: View[] = [this.content] + if (this.header) { + ret.push(this.header) + } + return ret + } + + setRefreshable(context: BridgeContext, refreshable: boolean) { + return this.nativeChannel(context, 'setRefreshable')(refreshable) + } + + setRefreshing(context: BridgeContext, refreshing: boolean) { + return this.nativeChannel(context, 'setRefreshing')(refreshing) + } + + isRefreshable(context: BridgeContext) { + return this.nativeChannel(context, 'isRefreshable')() as Promise + } + + isRefreshing(context: BridgeContext) { + return this.nativeChannel(context, 'isRefreshing')() as Promise + } + + toModel() { + this.dirtyProps.content = this.content.viewId + this.dirtyProps.header = (this.header || {}).viewId + return super.toModel() + } +} + +export function refreshable(config: IRefreshable) { + const ret = new Refreshable + ret.layoutConfig = layoutConfig().wrap() + for (let key in config) { + Reflect.set(ret, key, Reflect.get(config, key, config), ret) + } + return ret +} diff --git a/js-framework/src/ui/view.ts b/js-framework/src/ui/view.ts index 893bf4dc..baa1595f 100644 --- a/js-framework/src/ui/view.ts +++ b/js-framework/src/ui/view.ts @@ -266,7 +266,7 @@ export abstract class View implements Modeling, IView { nativeChannel(context: any, name: string) { let thisView: View | undefined = this - return function (...args: any) { + return function (args: any = undefined) { const func = context.shader.command const viewIds = [] while (thisView != undefined) { From 1f0a1a5e0ad3b5212cb642d685c9a91ac6af1259 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 10:36:23 +0800 Subject: [PATCH 07/35] feat:setEnable setRefreshing to false --- .../src/main/java/pub/doric/pullable/DoricSwipeLayout.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java index a83ca478..4ac43197 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java @@ -159,6 +159,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent private ValueAnimator headerViewAnimator; void reset() { + mRefreshing = false; if (headerViewAnimator != null && headerViewAnimator.isRunning()) { headerViewAnimator.cancel(); } @@ -199,8 +200,6 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent }); headerViewAnimator.setDuration(SCALE_DOWN_DURATION); headerViewAnimator.start(); - - } @Override From a5b07949bafa121c16e627ae4f0afc74045d8550 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 11:33:08 +0800 Subject: [PATCH 08/35] feat:fix view has no superview --- .../pub/doric/pullable/PullingListener.java | 20 +++++++++++++++++++ js-framework/src/ui/view.ts | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 Android/doric/src/main/java/pub/doric/pullable/PullingListener.java diff --git a/Android/doric/src/main/java/pub/doric/pullable/PullingListener.java b/Android/doric/src/main/java/pub/doric/pullable/PullingListener.java new file mode 100644 index 00000000..71df7b07 --- /dev/null +++ b/Android/doric/src/main/java/pub/doric/pullable/PullingListener.java @@ -0,0 +1,20 @@ +package pub.doric.pullable; + +/** + * @Description: pub.doric.pullable + * @Author: pengfei.zhou + * @CreateDate: 2019-11-25 + */ +public interface IPullable { + + void startAnimation(); + + void stopAnimation(); + + /** + * Set the amount of rotation to apply to the progress spinner. + * + * @param rotation Rotation is from [0..2] + */ + void setProgressRotation(float rotation); +} diff --git a/js-framework/src/ui/view.ts b/js-framework/src/ui/view.ts index baa1595f..70f942b0 100644 --- a/js-framework/src/ui/view.ts +++ b/js-framework/src/ui/view.ts @@ -316,6 +316,7 @@ export abstract class Superview extends View { toModel() { const subviews = [] for (let v of this.allSubviews()) { + v.superview = this if (v.isDirty()) { subviews.push(v.toModel()) } @@ -341,7 +342,6 @@ export abstract class Group extends Superview { } addChild(view: View) { - view.superview = this this.children.push(view) } } From c90547a1f044adb9ec83f117f818128b74c87d97 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 11:33:28 +0800 Subject: [PATCH 09/35] feat:update tsconfig incase uses dom lib --- demo/tsconfig.json | 2 +- js-framework/tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/tsconfig.json b/demo/tsconfig.json index 4d880db4..8a7c268d 100644 --- a/demo/tsconfig.json +++ b/demo/tsconfig.json @@ -4,7 +4,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ + "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ diff --git a/js-framework/tsconfig.json b/js-framework/tsconfig.json index d511f6a0..7946f238 100644 --- a/js-framework/tsconfig.json +++ b/js-framework/tsconfig.json @@ -5,7 +5,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ + "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ From 9a9482eeb5c3febbac152633b791524bd3a13fd2 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 11:34:02 +0800 Subject: [PATCH 10/35] feat:add RefreshableDemo --- .../pub/doric/pullable/DoricRefreshView.java | 31 +++++++++---------- .../java/pub/doric/pullable/IPullable.java | 27 ---------------- .../pub/doric/pullable/PullingListener.java | 2 +- .../pub/doric/pullable/RefreshableNode.java | 29 +++++++++++++++-- .../main/java/pub/doric/shader/ViewNode.java | 12 +++++++ demo/src/RefreshableDemo.ts | 12 +++++++ demo/src/utils.ts | 2 ++ js-framework/src/ui/refreshable.ts | 11 +++++++ 8 files changed, 80 insertions(+), 46 deletions(-) delete mode 100644 Android/doric/src/main/java/pub/doric/pullable/IPullable.java diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java b/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java index 2d404750..6ab3633e 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java +++ b/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java @@ -2,6 +2,7 @@ package pub.doric.pullable; import android.content.Context; import android.util.AttributeSet; +import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -17,10 +18,12 @@ import androidx.annotation.Nullable; * @Author: pengfei.zhou * @CreateDate: 2019-11-25 */ -public class DoricRefreshView extends FrameLayout implements IPullable { +public class DoricRefreshView extends FrameLayout implements PullingListener { private View content; private Animation.AnimationListener mListener; + private PullingListener mPullingListenr; + public DoricRefreshView(@NonNull Context context) { super(context); } @@ -50,33 +53,29 @@ public class DoricRefreshView extends FrameLayout implements IPullable { return content; } + + public void setPullingListenr(PullingListener listenr) { + this.mPullingListenr = listenr; + } + @Override public void startAnimation() { - if (content != null && content instanceof IPullable) { - ((IPullable) content).startAnimation(); + if (mPullingListenr != null) { + mPullingListenr.startAnimation(); } } @Override public void stopAnimation() { - if (content != null && content instanceof IPullable) { - ((IPullable) content).stopAnimation(); - } - } - - @Override - public int successAnimation() { - if (content != null && content instanceof IPullable) { - return ((IPullable) content).successAnimation(); - } else { - return 0; + if (mPullingListenr != null) { + mPullingListenr.stopAnimation(); } } @Override public void setProgressRotation(float rotation) { - if (content != null && content instanceof IPullable) { - ((IPullable) content).setProgressRotation(rotation); + if (mPullingListenr != null) { + mPullingListenr.setProgressRotation(rotation); } } diff --git a/Android/doric/src/main/java/pub/doric/pullable/IPullable.java b/Android/doric/src/main/java/pub/doric/pullable/IPullable.java deleted file mode 100644 index 83bb96af..00000000 --- a/Android/doric/src/main/java/pub/doric/pullable/IPullable.java +++ /dev/null @@ -1,27 +0,0 @@ -package pub.doric.pullable; - -/** - * @Description: pub.doric.pullable - * @Author: pengfei.zhou - * @CreateDate: 2019-11-25 - */ -public interface IPullable { - - void startAnimation(); - - void stopAnimation(); - - /** - * run the animation after pull request success and before stop animation - * - * @return the duration of success animation or 0 if no success animation - */ - int successAnimation(); - - /** - * Set the amount of rotation to apply to the progress spinner. - * - * @param rotation Rotation is from [0..1] - */ - void setProgressRotation(float rotation); -} diff --git a/Android/doric/src/main/java/pub/doric/pullable/PullingListener.java b/Android/doric/src/main/java/pub/doric/pullable/PullingListener.java index 71df7b07..6c2c3257 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/PullingListener.java +++ b/Android/doric/src/main/java/pub/doric/pullable/PullingListener.java @@ -5,7 +5,7 @@ package pub.doric.pullable; * @Author: pengfei.zhou * @CreateDate: 2019-11-25 */ -public interface IPullable { +public interface PullingListener { void startAnimation(); diff --git a/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java b/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java index 37fbb31a..329f8207 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java +++ b/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java @@ -1,5 +1,7 @@ package pub.doric.pullable; +import android.view.animation.Animation; + import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JavaValue; @@ -17,7 +19,7 @@ import pub.doric.shader.ViewNode; * @CreateDate: 2019-11-26 */ @DoricPlugin(name = "Refreshable") -public class RefreshableNode extends SuperNode { +public class RefreshableNode extends SuperNode implements PullingListener { private String mContentViewId; private ViewNode mContentNode; @@ -32,7 +34,9 @@ public class RefreshableNode extends SuperNode { @Override protected DoricSwipeLayout build() { - return new DoricSwipeLayout(getContext()); + DoricSwipeLayout doricSwipeLayout = new DoricSwipeLayout(getContext()); + doricSwipeLayout.getRefreshView().setPullingListenr(this); + return doricSwipeLayout; } @Override @@ -162,4 +166,25 @@ public class RefreshableNode extends SuperNode { public void isRefreshing(DoricPromise doricPromise) { doricPromise.resolve(new JavaValue(this.mView.isRefreshing())); } + + @Override + public void startAnimation() { + if (mHeaderNode != null) { + mHeaderNode.callJSResponse("startAnimation"); + } + } + + @Override + public void stopAnimation() { + if (mHeaderNode != null) { + mHeaderNode.callJSResponse("stopAnimation"); + } + } + + @Override + public void setProgressRotation(float rotation) { + if (mHeaderNode != null) { + mHeaderNode.callJSResponse("setProgressRotation", rotation); + } + } } diff --git a/Android/doric/src/main/java/pub/doric/shader/ViewNode.java b/Android/doric/src/main/java/pub/doric/shader/ViewNode.java index ee394eab..3a98a74f 100644 --- a/Android/doric/src/main/java/pub/doric/shader/ViewNode.java +++ b/Android/doric/src/main/java/pub/doric/shader/ViewNode.java @@ -257,4 +257,16 @@ public abstract class ViewNode extends DoricContextHolder { public int getHeight() { return mView.getHeight(); } + + @DoricMethod + public void setRotation(JSValue jsValue) { + float rotation = jsValue.asNumber().toFloat(); + while (rotation > 1) { + rotation = rotation - 1; + } + while (rotation < -1) { + rotation = rotation + 1; + } + doricLayer.setRotation(rotation * 360); + } } diff --git a/demo/src/RefreshableDemo.ts b/demo/src/RefreshableDemo.ts index 24d83750..a3b457ca 100644 --- a/demo/src/RefreshableDemo.ts +++ b/demo/src/RefreshableDemo.ts @@ -60,6 +60,18 @@ class RefreshableDemo extends Panel { refreshView.setRefreshable(context, false) } } as IText), + label('Rotate self').apply({ + width: 300, + height: 50, + bgColor: 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().center(), diff --git a/demo/src/utils.ts b/demo/src/utils.ts index a024952e..18debee8 100644 --- a/demo/src/utils.ts +++ b/demo/src/utils.ts @@ -1,5 +1,7 @@ import { Color, text, Stack, Text, layoutConfig, LayoutSpec, gravity } from "doric"; +export const icon_refresh = 'data:image/png;base64,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' + export const colors = [ "#70a1ff", "#7bed9f", diff --git a/js-framework/src/ui/refreshable.ts b/js-framework/src/ui/refreshable.ts index f1ca4704..1a73cb93 100644 --- a/js-framework/src/ui/refreshable.ts +++ b/js-framework/src/ui/refreshable.ts @@ -3,6 +3,7 @@ import { List } from "./list"; import { Scroller } from "./scroller"; import { BridgeContext } from "../runtime/global"; import { layoutConfig } from "./declarative"; +import { Image } from "./widgets"; export interface IRefreshable extends IView { content: List | Scroller @@ -58,3 +59,13 @@ export function refreshable(config: IRefreshable) { } return ret } + +export interface IPullable { + startAnimation(): void + stopAnimation(): void + setProgressRotation(rotation: number): void +} + +export class PullableView extends Image { + +} \ No newline at end of file From 208c635b8b14687e956fbb0f9b373b6baf5466f4 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 13:32:07 +0800 Subject: [PATCH 11/35] feat:add InjectEmpty to ignore too much logout --- .../doric/src/main/java/pub/doric/engine/DoricJSEngine.java | 6 ++++++ .../doric/src/main/java/pub/doric/utils/DoricConstant.java | 1 + iOS/Pod/Classes/Engine/DoricJSEngine.m | 4 +++- iOS/Pod/Classes/Util/DoricConstant.h | 1 + iOS/Pod/Classes/Util/DoricConstant.m | 1 + js-framework/src/ui/panel.ts | 4 +++- 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java b/Android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java index 7cc40445..a4bf460f 100644 --- a/Android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java +++ b/Android/doric/src/main/java/pub/doric/engine/DoricJSEngine.java @@ -96,6 +96,12 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time return null; } }); + mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_EMPTY, new JavaFunction() { + @Override + public JavaValue exec(JSDecoder[] args) { + return null; + } + }); mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_REQUIRE, new JavaFunction() { @Override public JavaValue exec(JSDecoder[] args) { diff --git a/Android/doric/src/main/java/pub/doric/utils/DoricConstant.java b/Android/doric/src/main/java/pub/doric/utils/DoricConstant.java index f4da7cdc..08a814b1 100644 --- a/Android/doric/src/main/java/pub/doric/utils/DoricConstant.java +++ b/Android/doric/src/main/java/pub/doric/utils/DoricConstant.java @@ -31,6 +31,7 @@ public class DoricConstant { public static final String INJECT_TIMER_SET = "nativeSetTimer"; public static final String INJECT_TIMER_CLEAR = "nativeClearTimer"; public static final String INJECT_BRIDGE = "nativeBridge"; + public static final String INJECT_EMPTY = "nativeEmpty"; public static final String TEMPLATE_CONTEXT_CREATE = "Reflect.apply(" + "function(doric,context,Entry,require,exports){" + "\n" + diff --git a/iOS/Pod/Classes/Engine/DoricJSEngine.m b/iOS/Pod/Classes/Engine/DoricJSEngine.m index 3559c0cb..12984ea8 100644 --- a/iOS/Pod/Classes/Engine/DoricJSEngine.m +++ b/iOS/Pod/Classes/Engine/DoricJSEngine.m @@ -59,7 +59,9 @@ - (void)initJSExecutor { [self.jsExecutor injectGlobalJSObject:INJECT_LOG obj:^(NSString *type, NSString *message) { DoricLog(@"JS:%@", message); }]; - + [self.jsExecutor injectGlobalJSObject:INJECT_EMPTY obj:^() { + + }]; [self.jsExecutor injectGlobalJSObject:INJECT_REQUIRE obj:^(NSString *name) { __strong typeof(_self) self = _self; if (!self) return NO; diff --git a/iOS/Pod/Classes/Util/DoricConstant.h b/iOS/Pod/Classes/Util/DoricConstant.h index 8256c9a9..06b34fd2 100644 --- a/iOS/Pod/Classes/Util/DoricConstant.h +++ b/iOS/Pod/Classes/Util/DoricConstant.h @@ -32,6 +32,7 @@ extern NSString *const INJECT_REQUIRE; extern NSString *const INJECT_TIMER_SET; extern NSString *const INJECT_TIMER_CLEAR; extern NSString *const INJECT_BRIDGE; +extern NSString *const INJECT_EMPTY; extern NSString *const TEMPLATE_CONTEXT_CREATE; diff --git a/iOS/Pod/Classes/Util/DoricConstant.m b/iOS/Pod/Classes/Util/DoricConstant.m index 6d936e1e..09a742a4 100644 --- a/iOS/Pod/Classes/Util/DoricConstant.m +++ b/iOS/Pod/Classes/Util/DoricConstant.m @@ -32,6 +32,7 @@ NSString *const INJECT_TIMER_SET = @"nativeSetTimer"; NSString *const INJECT_TIMER_CLEAR = @"nativeClearTimer"; NSString *const INJECT_BRIDGE = @"nativeBridge"; +NSString *const INJECT_EMPTY = @"nativeEmpty"; NSString *const TEMPLATE_CONTEXT_CREATE = @"Reflect.apply(" "function(doric,context,Entry,require,exports){" "\n" diff --git a/js-framework/src/ui/panel.ts b/js-framework/src/ui/panel.ts index a1473451..32115c37 100644 --- a/js-framework/src/ui/panel.ts +++ b/js-framework/src/ui/panel.ts @@ -31,6 +31,8 @@ export function NativeCall(target: Panel, propertyKey: string, descriptor: Prope type Frame = { width: number, height: number } +declare function nativeEmpty(): void + export abstract class Panel { context?: any onCreate() { } @@ -132,7 +134,7 @@ export abstract class Panel { private hookAfterNativeCall() { //Here insert a native call to ensure the promise is resolved done. - log('Check Dirty') + nativeEmpty() if (this.__root__.isDirty()) { const model = this.__root__.toModel() this.nativeRender(model) From 3dfa6c9770a15a44dc2d1ce86dc1a6b56ee0e3b4 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 13:33:03 +0800 Subject: [PATCH 12/35] feat:add Pullable and view's setRotation function --- .../main/java/pub/doric/shader/ViewNode.java | 5 ++++ .../main/java/pub/doric/utils/DoricUtils.java | 2 ++ demo/src/RefreshableDemo.ts | 28 ++++++++++++++----- js-framework/src/ui/refreshable.ts | 6 +++- js-framework/src/ui/view.ts | 24 ++++++++++++++++ 5 files changed, 57 insertions(+), 8 deletions(-) diff --git a/Android/doric/src/main/java/pub/doric/shader/ViewNode.java b/Android/doric/src/main/java/pub/doric/shader/ViewNode.java index 3a98a74f..b7df0e5c 100644 --- a/Android/doric/src/main/java/pub/doric/shader/ViewNode.java +++ b/Android/doric/src/main/java/pub/doric/shader/ViewNode.java @@ -269,4 +269,9 @@ public abstract class ViewNode extends DoricContextHolder { } doricLayer.setRotation(rotation * 360); } + + @DoricMethod + public float getRotation() { + return doricLayer.getRotation() / 360; + } } diff --git a/Android/doric/src/main/java/pub/doric/utils/DoricUtils.java b/Android/doric/src/main/java/pub/doric/utils/DoricUtils.java index e44b7f71..6f1b237d 100644 --- a/Android/doric/src/main/java/pub/doric/utils/DoricUtils.java +++ b/Android/doric/src/main/java/pub/doric/utils/DoricUtils.java @@ -81,6 +81,8 @@ public class DoricUtils { return new JavaValue((Integer) arg); } else if (arg instanceof Long) { return new JavaValue((Long) arg); + } else if (arg instanceof Float) { + return new JavaValue((Float) arg); } else if (arg instanceof Double) { return new JavaValue((Double) arg); } else if (arg instanceof Boolean) { diff --git a/demo/src/RefreshableDemo.ts b/demo/src/RefreshableDemo.ts index a3b457ca..280ed5ef 100644 --- a/demo/src/RefreshableDemo.ts +++ b/demo/src/RefreshableDemo.ts @@ -1,16 +1,30 @@ -import { refreshable, Group, Panel, navbar, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text, scroller, layoutConfig, image, IView, IVLayout, ScaleType, modal, IText, network, navigator } from "doric"; -import { title, label, colors } from "./utils"; +import { refreshable, Group, Panel, pullable, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text, scroller, layoutConfig, image, IView, IVLayout, ScaleType, modal, IText, network, navigator, stack, Image } from "doric"; +import { title, label, colors, icon_refresh } from "./utils"; @Entry class RefreshableDemo extends Panel { build(rootView: Group): void { + let refreshImage: Image let refreshView = refreshable({ layoutConfig: layoutConfig().atmost(), - header: text({ - text: "This is Header", - width: 100, - height: 100, - layoutConfig: layoutConfig().exactly(), + header: pullable(context, + stack([ + image({ + layoutConfig: layoutConfig().exactly().m({ top: 50, bottom: 10, }), + width: 30, + height: 30, + imageBase64: icon_refresh, + }).also(v => refreshImage = v), + ]), { + startAnimation: () => { + log('startAnimation') + }, + stopAnimation: () => { + log('stopAnimation') + }, + setProgressRotation: (rotation: number) => { + refreshImage.setRotation(context, rotation) + }, }), content: scroller(vlayout([ title("Refreshable Demo"), diff --git a/js-framework/src/ui/refreshable.ts b/js-framework/src/ui/refreshable.ts index 1a73cb93..35de57d7 100644 --- a/js-framework/src/ui/refreshable.ts +++ b/js-framework/src/ui/refreshable.ts @@ -66,6 +66,10 @@ export interface IPullable { setProgressRotation(rotation: number): void } -export class PullableView extends Image { +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) + return v } \ No newline at end of file diff --git a/js-framework/src/ui/view.ts b/js-framework/src/ui/view.ts index 70f942b0..1cabf6e0 100644 --- a/js-framework/src/ui/view.ts +++ b/js-framework/src/ui/view.ts @@ -18,6 +18,7 @@ import { Modeling, Model, obj2Model } from "../util/types"; import { uniqueId } from "../util/uniqueId"; import { Gravity } from "../util/gravity"; import { loge } from "../util/log"; +import { BridgeContext } from "../runtime/global"; export enum LayoutSpec { EXACTLY = 0, @@ -281,6 +282,29 @@ export abstract class View implements Modeling, IView { return Reflect.apply(func, undefined, [params]) as Promise } } + + getWidth(context: BridgeContext) { + return this.nativeChannel(context, 'getWidth')() as Promise + } + + getHeight(context: BridgeContext) { + return this.nativeChannel(context, 'getHeight')() as Promise + } + + /** + * + * @param rotation [0..1] + */ + setRotation(context: BridgeContext, rotation: number) { + return this.nativeChannel(context, 'setRotation')(rotation) + } + /** + * + * @return rotation [0..1] + */ + getRotation(context: BridgeContext) { + return this.nativeChannel(context, 'getRotation')() as Promise + } } export abstract class Superview extends View { From 84b9ec0f22351ed70e523fb64c783ca5d8aae426 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 13:39:04 +0800 Subject: [PATCH 13/35] feat:add OnRefresh Callback for Android --- .../main/java/pub/doric/pullable/RefreshableNode.java | 10 ++++++++-- demo/src/RefreshableDemo.ts | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java b/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java index 329f8207..3e87de2a 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java +++ b/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java @@ -1,7 +1,5 @@ package pub.doric.pullable; -import android.view.animation.Animation; - import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JavaValue; @@ -45,6 +43,14 @@ public class RefreshableNode extends SuperNode implements Pull mContentViewId = prop.asString().value(); } else if ("header".equals(name)) { mHeaderViewId = prop.asString().value(); + } else if ("onRefresh".equals(name)) { + final String funcId = prop.asString().value(); + mView.setOnRefreshListener(new DoricSwipeLayout.OnRefreshListener() { + @Override + public void onRefresh() { + callJSResponse(funcId); + } + }); } else { super.blend(view, name, prop); } diff --git a/demo/src/RefreshableDemo.ts b/demo/src/RefreshableDemo.ts index 280ed5ef..743da1e6 100644 --- a/demo/src/RefreshableDemo.ts +++ b/demo/src/RefreshableDemo.ts @@ -7,6 +7,12 @@ class RefreshableDemo extends Panel { let refreshImage: Image let refreshView = refreshable({ layoutConfig: layoutConfig().atmost(), + onRefresh: () => { + log('onRefresh') + setTimeout(() => { + refreshView.setRefreshing(context, false) + }, 5000) + }, header: pullable(context, stack([ image({ From 0b1174c3fd4bd8315467da307e9d0ecb7ef11987 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 14:06:44 +0800 Subject: [PATCH 14/35] feat:Refreshable +list --- demo/src/ListDemo.ts | 156 +++++++++++++++++++----------------- demo/src/utils.ts | 26 +++++- js-framework/src/ui/list.ts | 4 + 3 files changed, 112 insertions(+), 74 deletions(-) diff --git a/demo/src/ListDemo.ts b/demo/src/ListDemo.ts index a0ccb61a..b3de5c46 100644 --- a/demo/src/ListDemo.ts +++ b/demo/src/ListDemo.ts @@ -1,15 +1,11 @@ -import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text } from "doric"; -const colors = [ - "#f0932b", - "#eb4d4b", - "#6ab04c", - "#e056fd", - "#686de0", - "#30336b", -] +import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text, refreshable, Refreshable, ListItem } from "doric"; +import { rotatedArrow, colors } from "./utils"; +import { isObject } from "util"; @Entry class ListPanel extends Panel { build(rootView: Group): void { + let refreshView: Refreshable + let offset = Math.ceil(Math.random() * colors.length) vlayout([ text({ text: "ListDemo", @@ -23,76 +19,90 @@ class ListPanel extends Panel { textAlignment: gravity().center(), height: 50, }), - list({ - itemCount: 1000, - renderItem: (idx: number) => { - let counter!: Text - return listItem( - hlayout([ - text({ - layoutConfig: { - widthSpec: LayoutSpec.WRAP_CONTENT, - heightSpec: LayoutSpec.EXACTLY, - alignment: gravity().center(), - }, - text: `Cell At Line ${idx}`, - textAlignment: gravity().center(), - textColor: Color.parse("#ffffff"), - textSize: 20, - height: 50, - }), - text({ - textColor: Color.parse("#ffffff"), - textSize: 20, - text: "", - }).also(it => { - counter = it - it.layoutConfig = { - widthSpec: LayoutSpec.WRAP_CONTENT, - heightSpec: LayoutSpec.WRAP_CONTENT, - margin: { - left: 10, + refreshView = refreshable({ + onRefresh: () => { + refreshView.setRefreshing(context, false).then(() => { + (refreshView.content as List).also(it => { + it.reset() + offset = Math.ceil(Math.random() * colors.length) + it.itemCount = 40 + it.renderItem = (idx: number) => { + let counter!: Text + return listItem( + hlayout([ + text({ + layoutConfig: { + widthSpec: LayoutSpec.WRAP_CONTENT, + heightSpec: LayoutSpec.EXACTLY, + alignment: gravity().center(), + }, + text: `Cell At Line ${idx}`, + textAlignment: gravity().center(), + textColor: Color.parse("#ffffff"), + textSize: 20, + height: 50, + }), + text({ + textColor: Color.parse("#ffffff"), + textSize: 20, + text: "", + }).also(it => { + counter = it + it.layoutConfig = { + widthSpec: LayoutSpec.WRAP_CONTENT, + heightSpec: LayoutSpec.WRAP_CONTENT, + margin: { + left: 10, + } + } + }) + ]).also(it => { + it.layoutConfig = { + widthSpec: LayoutSpec.AT_MOST, + heightSpec: LayoutSpec.WRAP_CONTENT, + margin: { + bottom: 2, + } + } + it.gravity = gravity().center() + it.bgColor = colors[(idx + offset) % colors.length] + let clicked = 0 + it.onClick = () => { + counter.text = `Item Clicked ${++clicked}` + } + }) + ).also(it => { + it.layoutConfig = { + widthSpec: LayoutSpec.AT_MOST, + heightSpec: LayoutSpec.WRAP_CONTENT, } - } - }) - ]).also(it => { - it.layoutConfig = { - widthSpec: LayoutSpec.AT_MOST, - heightSpec: LayoutSpec.WRAP_CONTENT, - margin: { - bottom: 2, - } - } - it.gravity = gravity().center() - it.bgColor = Color.parse(colors[idx % colors.length]) - let clicked = 0 - it.onClick = () => { - counter.text = `Item Clicked ${++clicked}` + it.onClick = () => { + log(`Click item at ${idx}`) + it.height += 10 + it.nativeChannel(context, "getWidth")().then( + resolve => { + log(`resolve,${resolve}`) + }, + reject => { + log(`reject,${reject}`) + }) + } + }) } }) - ).also(it => { - it.layoutConfig = { - widthSpec: LayoutSpec.AT_MOST, - heightSpec: LayoutSpec.WRAP_CONTENT, - } - it.onClick = () => { - log(`Click item at ${idx}`) - it.height += 10 - it.nativeChannel(context, "getWidth")().then( - resolve => { - log(`resolve,${resolve}`) - }, - reject => { - log(`reject,${reject}`) - }) - } }) }, - layoutConfig: { - widthSpec: LayoutSpec.AT_MOST, - heightSpec: LayoutSpec.AT_MOST, - }, + header: rotatedArrow(context), + content: list({ + itemCount: 0, + renderItem: () => new ListItem, + layoutConfig: { + widthSpec: LayoutSpec.AT_MOST, + heightSpec: LayoutSpec.AT_MOST, + }, + }), }), + ]).also(it => { it.layoutConfig = { widthSpec: LayoutSpec.AT_MOST, diff --git a/demo/src/utils.ts b/demo/src/utils.ts index 18debee8..8bb513b6 100644 --- a/demo/src/utils.ts +++ b/demo/src/utils.ts @@ -1,4 +1,5 @@ -import { Color, text, Stack, Text, layoutConfig, LayoutSpec, gravity } from "doric"; +import { Color, text, Stack, Text, layoutConfig, LayoutSpec, gravity, pullable, stack, image, Image, BridgeContext } from "doric"; +import { log } from "util"; export const icon_refresh = 'data:image/png;base64,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' @@ -47,4 +48,27 @@ export function title(str: string) { textAlignment: gravity().center(), height: 50, }) +} + +export function rotatedArrow(context: BridgeContext) { + let refreshImage: Image + return pullable(context, + stack([ + image({ + layoutConfig: layoutConfig().exactly().m({ top: 50, bottom: 10, }), + width: 30, + height: 30, + imageBase64: icon_refresh, + }).also(v => refreshImage = v), + ]), { + startAnimation: () => { + log('startAnimation') + }, + stopAnimation: () => { + log('stopAnimation') + }, + setProgressRotation: (rotation: number) => { + refreshImage.setRotation(context, rotation) + }, + }) } \ No newline at end of file diff --git a/js-framework/src/ui/list.ts b/js-framework/src/ui/list.ts index b59091cd..780c2302 100644 --- a/js-framework/src/ui/list.ts +++ b/js-framework/src/ui/list.ts @@ -57,6 +57,10 @@ export class List extends Superview implements IList { @Property batchCount = 15 + reset() { + this.cachedViews.clear() + this.itemCount = 0 + } private getItem(itemIdx: number) { let view = this.cachedViews.get(`${itemIdx}`) if (view === undefined) { From 08e42bacdd5dce224921ad1b953f77ec6b7cb8b7 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 15:51:39 +0800 Subject: [PATCH 15/35] feat:change moment of setting scrollview's contentsize --- iOS/Pod/Classes/Shader/DoricScrollerNode.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.m b/iOS/Pod/Classes/Shader/DoricScrollerNode.m index cc951f12..c492e560 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -29,10 +29,6 @@ @implementation DoricScrollView - (void)layoutSubviews { [super layoutSubviews]; - if (self.subviews.count > 0) { - UIView *child = self.subviews[0]; - [self setContentSize:child.frame.size]; - } } - (CGSize)sizeThatFits:(CGSize)size { @@ -91,6 +87,13 @@ - (void)blend:(NSDictionary *)props { [self.view addSubview:it.view]; }]; } + [self.view also:^(UIScrollView *it) { + if (it.subviews.count > 0) { + UIView *child = it.subviews[0]; + CGSize size = [child sizeThatFits:it.frame.size]; + [it setContentSize:size]; + } + }]; } - (void)blendView:(UIScrollView *)view forPropName:(NSString *)name propValue:(id)prop { From 74cee4f91b055453e51872ab8b5ae863f27698e2 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 15:57:48 +0800 Subject: [PATCH 16/35] feat:rename package name --- Android/app/src/main/java/pub/doric/demo/MainActivity.java | 4 +--- .../app/src/main/java/pub/doric/demo/PullableActivity.java | 2 +- Android/app/src/main/res/layout/activity_main.xml | 4 ++-- Android/app/src/main/res/layout/activity_pullable.xml | 2 +- Android/doric/src/main/java/pub/doric/DoricRegistry.java | 2 +- .../pub/doric/{pullable => refresh}/DoricRefreshView.java | 3 +-- .../pub/doric/{pullable => refresh}/DoricSwipeLayout.java | 2 +- .../java/pub/doric/{pullable => refresh}/PullingListener.java | 2 +- .../java/pub/doric/{pullable => refresh}/RefreshableNode.java | 2 +- 9 files changed, 10 insertions(+), 13 deletions(-) rename Android/doric/src/main/java/pub/doric/{pullable => refresh}/DoricRefreshView.java (98%) rename Android/doric/src/main/java/pub/doric/{pullable => refresh}/DoricSwipeLayout.java (99%) rename Android/doric/src/main/java/pub/doric/{pullable => refresh}/PullingListener.java (93%) rename Android/doric/src/main/java/pub/doric/{pullable => refresh}/RefreshableNode.java (99%) diff --git a/Android/app/src/main/java/pub/doric/demo/MainActivity.java b/Android/app/src/main/java/pub/doric/demo/MainActivity.java index ad02e812..b9153c44 100644 --- a/Android/app/src/main/java/pub/doric/demo/MainActivity.java +++ b/Android/app/src/main/java/pub/doric/demo/MainActivity.java @@ -29,15 +29,13 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import org.w3c.dom.Text; - import java.io.IOException; import java.util.ArrayList; import java.util.List; import pub.doric.DoricActivity; import pub.doric.devkit.ui.DemoDebugActivity; -import pub.doric.pullable.DoricSwipeLayout; +import pub.doric.refresh.DoricSwipeLayout; import pub.doric.utils.DoricUtils; public class MainActivity extends AppCompatActivity { diff --git a/Android/app/src/main/java/pub/doric/demo/PullableActivity.java b/Android/app/src/main/java/pub/doric/demo/PullableActivity.java index 615f27c5..2ce73a2a 100644 --- a/Android/app/src/main/java/pub/doric/demo/PullableActivity.java +++ b/Android/app/src/main/java/pub/doric/demo/PullableActivity.java @@ -6,7 +6,7 @@ import android.graphics.Color; import android.os.Bundle; import android.widget.FrameLayout; -import pub.doric.pullable.DoricSwipeLayout; +import pub.doric.refresh.DoricSwipeLayout; public class PullableActivity extends AppCompatActivity { diff --git a/Android/app/src/main/res/layout/activity_main.xml b/Android/app/src/main/res/layout/activity_main.xml index 95619501..8a4718b2 100644 --- a/Android/app/src/main/res/layout/activity_main.xml +++ b/Android/app/src/main/res/layout/activity_main.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/Android/app/src/main/res/layout/activity_pullable.xml b/Android/app/src/main/res/layout/activity_pullable.xml index e9bad365..c6923232 100644 --- a/Android/app/src/main/res/layout/activity_pullable.xml +++ b/Android/app/src/main/res/layout/activity_pullable.xml @@ -6,7 +6,7 @@ android:layout_height="match_parent" tools:context=".PullableActivity"> - diff --git a/Android/doric/src/main/java/pub/doric/DoricRegistry.java b/Android/doric/src/main/java/pub/doric/DoricRegistry.java index c41c1b5a..9919509f 100644 --- a/Android/doric/src/main/java/pub/doric/DoricRegistry.java +++ b/Android/doric/src/main/java/pub/doric/DoricRegistry.java @@ -25,7 +25,7 @@ import pub.doric.plugin.NavigatorPlugin; import pub.doric.plugin.NetworkPlugin; import pub.doric.plugin.ShaderPlugin; import pub.doric.plugin.StoragePlugin; -import pub.doric.pullable.RefreshableNode; +import pub.doric.refresh.RefreshableNode; import pub.doric.shader.HLayoutNode; import pub.doric.shader.ImageNode; import pub.doric.shader.ScrollerNode; diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java b/Android/doric/src/main/java/pub/doric/refresh/DoricRefreshView.java similarity index 98% rename from Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java rename to Android/doric/src/main/java/pub/doric/refresh/DoricRefreshView.java index 6ab3633e..8b1ded39 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricRefreshView.java +++ b/Android/doric/src/main/java/pub/doric/refresh/DoricRefreshView.java @@ -1,8 +1,7 @@ -package pub.doric.pullable; +package pub.doric.refresh; import android.content.Context; import android.util.AttributeSet; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; diff --git a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java b/Android/doric/src/main/java/pub/doric/refresh/DoricSwipeLayout.java similarity index 99% rename from Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java rename to Android/doric/src/main/java/pub/doric/refresh/DoricSwipeLayout.java index 4ac43197..411f13ef 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/DoricSwipeLayout.java +++ b/Android/doric/src/main/java/pub/doric/refresh/DoricSwipeLayout.java @@ -1,4 +1,4 @@ -package pub.doric.pullable; +package pub.doric.refresh; import android.animation.Animator; import android.animation.ValueAnimator; diff --git a/Android/doric/src/main/java/pub/doric/pullable/PullingListener.java b/Android/doric/src/main/java/pub/doric/refresh/PullingListener.java similarity index 93% rename from Android/doric/src/main/java/pub/doric/pullable/PullingListener.java rename to Android/doric/src/main/java/pub/doric/refresh/PullingListener.java index 6c2c3257..c09ab2c4 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/PullingListener.java +++ b/Android/doric/src/main/java/pub/doric/refresh/PullingListener.java @@ -1,4 +1,4 @@ -package pub.doric.pullable; +package pub.doric.refresh; /** * @Description: pub.doric.pullable diff --git a/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java b/Android/doric/src/main/java/pub/doric/refresh/RefreshableNode.java similarity index 99% rename from Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java rename to Android/doric/src/main/java/pub/doric/refresh/RefreshableNode.java index 3e87de2a..c6f1d1ce 100644 --- a/Android/doric/src/main/java/pub/doric/pullable/RefreshableNode.java +++ b/Android/doric/src/main/java/pub/doric/refresh/RefreshableNode.java @@ -1,4 +1,4 @@ -package pub.doric.pullable; +package pub.doric.refresh; import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSValue; From deada07e8d028dbc1cb619c77a64329f38d21171 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 20:15:16 +0800 Subject: [PATCH 17/35] iOS SwipeLayout --- demo/src/ImageDemo.ts | 5 +- demo/src/ScrollerDemo.ts | 83 ++++-------- demo/src/image_base64.ts | 2 + iOS/Pod/Classes/DoricRegistry.m | 2 + .../Classes/Refresh/DoricRefreshableNode.h | 10 ++ .../Classes/Refresh/DoricRefreshableNode.m | 128 ++++++++++++++++++ .../Classes/Refresh/DoricSwipeRefreshLayout.h | 22 +++ .../Classes/Refresh/DoricSwipeRefreshLayout.m | 118 ++++++++++++++++ iOS/Pod/Classes/Shader/DoricLayouts.h | 4 + iOS/Pod/Classes/Shader/DoricLayouts.m | 41 +++++- iOS/Pod/Classes/Shader/DoricScrollerNode.h | 6 +- iOS/Pod/Classes/Shader/DoricScrollerNode.m | 32 +++-- 12 files changed, 375 insertions(+), 78 deletions(-) create mode 100644 demo/src/image_base64.ts create mode 100644 iOS/Pod/Classes/Refresh/DoricRefreshableNode.h create mode 100644 iOS/Pod/Classes/Refresh/DoricRefreshableNode.m create mode 100644 iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h create mode 100644 iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m diff --git a/demo/src/ImageDemo.ts b/demo/src/ImageDemo.ts index 109c99bb..a26c4cee 100644 --- a/demo/src/ImageDemo.ts +++ b/demo/src/ImageDemo.ts @@ -1,7 +1,8 @@ import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text, scroller, layoutConfig, image, IView, IVLayout, ScaleType } from "doric"; import { colors, label } from "./utils"; +import { img_base64 } from "./image_base64"; const imageUrl = 'https://img.zcool.cn/community/01e75b5da933daa801209e1ffa4649.jpg@1280w_1l_2o_100sh.jpg' -const imageBase64 = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4Qm8aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA0LjQuMC1FeGl2MiI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+IDxkYzpjcmVhdG9yPiA8cmRmOlNlcT4gPHJkZjpsaT5WZWN0b3JTdG9jay5jb20vNzMxNTkwPC9yZGY6bGk+IDwvcmRmOlNlcT4gPC9kYzpjcmVhdG9yPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwKDAwLCgsLDQ4SEA0OEQ4LCxAWEBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJBQUJFA0LDRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU/8AAEQgDDAPoAwERAAIRAQMRAf/EAB0AAQABBAMBAAAAAAAAAAAAAAAHBAUGCAEC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Nbqew6Az6PpwT0NIS/dVFecJJEpxOGVyI1j49XdDy62Zgj15eOT65qP/AAa3J8oAcvHJ9c1H/g1uT5QA5eOT65qP/BrcnygBy8cn1zUf+DW5PlAHKdOSUnPVuekpI+HLDa5Cz/jAGBXNjZZN2z+SE5u12apnrck6dhlcsGZnx74YdQ598CsRvLTJuPB6nMVOgYrVSrMLfJhqiVexqnKQazSo05SJ7rbhFmRFkTq1bcySeRgjZnzLyx3re0aiuGrRJbF1XXWZ9VrDk9lTb63t3U2nMlER5aqNbb0VqPoiLDb8FAAAAAAAAAAAAAAAAAAAAAAAAAHCi2GA0dwcz5qHpC5KMj87tL2kf/6cQVludk501zujFwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmu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HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCmpVwrWrzVHDg1pUk/OFL2KIy+jkgN5dYur2jBQlZnwH2gHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8/dMywk4xac2DNgT7ir1BodXoE9cldBnHGd1mt2cSZHkaeFBEeaT2Aksl5l7YPsnYp/CFHyItIop3mUeGVTlRJMrEHEqTIiKNcd16tsrWyo8szQZsGaT2FtLIBUcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38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' + @Entry class ImageDemo extends Panel { build(rootView: Group): void { @@ -82,7 +83,7 @@ class ImageDemo extends Panel { }), label('ImageBase64'), image({ - imageBase64, + imageBase64: img_base64, width: 300, height: 300, border: { diff --git a/demo/src/ScrollerDemo.ts b/demo/src/ScrollerDemo.ts index 153ffcb8..7981e123 100644 --- a/demo/src/ScrollerDemo.ts +++ b/demo/src/ScrollerDemo.ts @@ -1,59 +1,34 @@ -import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, scroller } from "doric"; -const colors = [ - "#f0932b", - "#eb4d4b", - "#6ab04c", - "#e056fd", - "#686de0", - "#30336b", -] +import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, scroller, layoutConfig } from "doric"; +import { label } from "./utils"; + @Entry class ScrollerPanel extends Panel { build(rootView: Group): void { - rootView.addChild(scroller(vlayout( - [ - // ...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5].map(e => text({ - // text: colors[e % colors.length], - // textColor: Color.parse('#ffffff'), - // textSize: 20, - // bgColor: Color.parse(colors[e % colors.length]), - // layoutConfig: { - // widthSpec: LayoutSpec.EXACTLY, - // heightSpec: LayoutSpec.EXACTLY, - // }, - // width: 200, - // height: 50, - // })), - ...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5].map(i => hlayout([ - ...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5].map(j => text({ - text: colors[(i + j) % colors.length], - textColor: Color.parse('#ffffff'), - textSize: 20, - bgColor: Color.parse(colors[(i + j) % colors.length]), - layoutConfig: { - widthSpec: LayoutSpec.EXACTLY, - heightSpec: LayoutSpec.EXACTLY, - }, - width: 80, - height: 50, - })), - ]).also(it => it.space = 20)), - hlayout([ - ...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5].map(e => text({ - text: colors[e % colors.length], - textColor: Color.parse('#ffffff'), - textSize: 20, - bgColor: Color.parse(colors[e % colors.length]), - layoutConfig: { - widthSpec: LayoutSpec.EXACTLY, - heightSpec: LayoutSpec.EXACTLY, - }, - width: 200, - height: 50, - })), - ] - ), - ] - ).also(it => it.space = 20))) + scroller( + vlayout([ + scroller( + vlayout(new Array(100).fill(1).map(e => label('Scroll Content'))) + ).apply({ + layoutConfig: layoutConfig().exactly(), + width: 300, + height: 500, + bgColor: Color.RED, + }), + scroller( + vlayout(new Array(100).fill(1).map(e => label('Scroll Content'))) + ).apply({ + layoutConfig: layoutConfig().exactly(), + width: 300, + height: 500, + bgColor: Color.BLUE, + }) + ]) + ) + .apply({ + layoutConfig: layoutConfig().atmost().h(LayoutSpec.EXACTLY), + height: 500, + bgColor: Color.YELLOW, + }) + .in(rootView) } } \ No newline at end of file diff --git a/demo/src/image_base64.ts b/demo/src/image_base64.ts new file mode 100644 index 00000000..9eb105a6 --- /dev/null +++ b/demo/src/image_base64.ts @@ -0,0 +1,2 @@ +export const img_base64 = + 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4Qm8aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA0LjQuMC1FeGl2MiI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+IDxkYzpjcmVhdG9yPiA8cmRmOlNlcT4gPHJkZjpsaT5WZWN0b3JTdG9jay5jb20vNzMxNTkwPC9yZGY6bGk+IDwvcmRmOlNlcT4gPC9kYzpjcmVhdG9yPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwKDAwLCgsLDQ4SEA0OEQ4LCxAWEBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJBQUJFA0LDRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU/8AAEQgDDAPoAwERAAIRAQMRAf/EAB0AAQABBAMBAAAAAAAAAAAAAAAHBAUGCAEC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Nbqew6Az6PpwT0NIS/dVFecJJEpxOGVyI1j49XdDy62Zgj15eOT65qP/AAa3J8oAcvHJ9c1H/g1uT5QA5eOT65qP/BrcnygBy8cn1zUf+DW5PlAHKdOSUnPVuekpI+HLDa5Cz/jAGBXNjZZN2z+SE5u12apnrck6dhlcsGZnx74YdQ598CsRvLTJuPB6nMVOgYrVSrMLfJhqiVexqnKQazSo05SJ7rbhFmRFkTq1bcySeRgjZnzLyx3re0aiuGrRJbF1XXWZ9VrDk9lTb63t3U2nMlER5aqNbb0VqPoiLDb8FAAAAAAAAAAAAAAAAAAAAAAAAAHCi2GA0dwcz5qHpC5KMj87tL2kf/6cQVludk501zujFwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmud0YYGTnTXO6MMDJzprndGGBk501zujDAyc6a53RhgZOdNc7owwMnOmu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HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCjd5HSnftZgUbvI6U79rMCmpVwrWrzVHDg1pUk/OFL2KIy+jkgN5dYur2jBQlZnwH2gHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8/dMywk4xac2DNgT7ir1BodXoE9cldBnHGd1mt2cSZHkaeFBEeaT2Aksl5l7YPsnYp/CFHyItIop3mUeGVTlRJMrEHEqTIiKNcd16tsrWyo8szQZsGaT2FtLIBUcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38iAcy0w99kzFHv+38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' \ No newline at end of file diff --git a/iOS/Pod/Classes/DoricRegistry.m b/iOS/Pod/Classes/DoricRegistry.m index c3e84485..0d7f9ea6 100644 --- a/iOS/Pod/Classes/DoricRegistry.m +++ b/iOS/Pod/Classes/DoricRegistry.m @@ -37,6 +37,7 @@ #import "DoricStoragePlugin.h" #import "DoricNavigatorPlugin.h" #import "DoricNavBarPlugin.h" +#import "DoricRefreshableNode.h" @interface DoricRegistry () @@ -76,6 +77,7 @@ - (void)innerRegister { [self registerViewNode:DoricScrollerNode.class withName:@"Scroller"]; [self registerViewNode:DoricSliderNode.class withName:@"Slider"]; [self registerViewNode:DoricSlideItemNode.class withName:@"SlideItem"]; + [self registerViewNode:DoricRefreshableNode.class withName:@"Refreshable"]; } - (void)registerJSBundle:(NSString *)bundle withName:(NSString *)name { diff --git a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.h b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.h new file mode 100644 index 00000000..61bb6845 --- /dev/null +++ b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.h @@ -0,0 +1,10 @@ +// +// Created by pengfei.zhou on 2019/11/26. +// + +#import +#import "DoricSuperNode.h" +#import "DoricSwipeRefreshLayout.h" + +@interface DoricRefreshableNode : DoricSuperNode +@end \ No newline at end of file diff --git a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m new file mode 100644 index 00000000..3406fcb1 --- /dev/null +++ b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m @@ -0,0 +1,128 @@ +// +// Created by pengfei.zhou on 2019/11/26. +// + +#import "DoricRefreshableNode.h" +#import "Doric.h" + +@interface DoricRefreshableNode () +@property(nonatomic, strong) DoricViewNode *contentNode; +@property(nonatomic, copy) NSString *contentViewId; +@property(nonatomic, strong) DoricViewNode *headerNode; +@property(nonatomic, copy) NSString *headerViewId; +@end + +@implementation DoricRefreshableNode +- (DoricSwipeRefreshLayout *)build { + return [DoricSwipeRefreshLayout new]; +} + +- (void)blendView:(DoricSwipeRefreshLayout *)view forPropName:(NSString *)name propValue:(id)prop { + if ([@"content" isEqualToString:name]) { + self.contentViewId = prop; + } else if ([@"header" isEqualToString:name]) { + self.headerViewId = prop; + } else if ([@"onRefresh" isEqualToString:name]) { + __weak typeof(self) _self = self; + NSString *funcId = prop; + self.view.onRefreshBlock = ^{ + __strong typeof(_self) self = _self; + [self callJSResponse:funcId, nil]; + }; + } else { + [super blendView:view forPropName:name propValue:prop]; + } +} + +- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId { + if ([viewId isEqualToString:self.contentViewId]) { + return self.contentNode; + } else if ([viewId isEqualToString:self.headerViewId]) { + return self.headerNode; + } else { + return nil; + } +} + +- (void)blend:(NSDictionary *)props { + [super blend:props]; + [self blendHeader]; + [self blendContent]; +} + +- (void)blendContent { + NSDictionary *contentModel = [self subModelOf:self.contentViewId]; + if (!contentModel) { + return; + } + NSString *viewId = contentModel[@"id"]; + NSString *type = contentModel[@"type"]; + NSDictionary *childProps = contentModel[@"props"]; + if (self.contentNode) { + if ([self.contentNode.viewId isEqualToString:viewId]) { + //skip + } else { + if (self.reusable && [type isEqualToString:self.contentNode.type]) { + [self.contentNode also:^(DoricViewNode *it) { + it.viewId = viewId; + [it blend:childProps]; + }]; + } else { + self.contentNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) { + it.viewId = viewId; + [it initWithSuperNode:self]; + [it blend:childProps]; + self.view.contentView = it.view; + }]; + } + } + } else { + self.contentNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) { + it.viewId = viewId; + [it initWithSuperNode:self]; + [it blend:childProps]; + self.view.contentView = it.view; + }]; + } +} + +- (void)blendHeader { + NSDictionary *headerModel = [self subModelOf:self.headerViewId]; + if (!headerModel) { + return; + } + NSString *viewId = headerModel[@"id"]; + NSString *type = headerModel[@"type"]; + NSDictionary *childProps = headerModel[@"props"]; + if (self.headerNode) { + if ([self.headerNode.viewId isEqualToString:viewId]) { + //skip + } else { + if (self.reusable && [type isEqualToString:self.headerNode.type]) { + [self.headerNode also:^(DoricViewNode *it) { + it.viewId = viewId; + [it blend:childProps]; + }]; + } else { + self.headerNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) { + it.viewId = viewId; + [it initWithSuperNode:self]; + [it blend:childProps]; + self.view.headerView = it.view; + }]; + } + } + } else { + self.headerNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) { + it.viewId = viewId; + [it initWithSuperNode:self]; + [it blend:childProps]; + self.view.headerView = it.view; + }]; + } +} + +- (void)blendSubNode:(NSDictionary *)subModel { + [[self subNodeWithViewId:subModel[@"id"]] blend:subModel[@"props"]]; +} +@end diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h new file mode 100644 index 00000000..45725251 --- /dev/null +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h @@ -0,0 +1,22 @@ +// +// Created by pengfei.zhou on 2019/11/26. +// + +#import + +@protocol DoricSwipePullingDelegate +- (void)startAnimation; + +- (void)stopAnimation; + +- (void)setProgressRotation:(CGFloat)rotation; +@end + +@interface DoricSwipeRefreshLayout : UIScrollView +@property(nonatomic, strong) UIView *contentView; +@property(nonatomic, strong) UIView *headerView; +@property(nonatomic, assign) BOOL refreshable; +@property(nonatomic, assign) BOOL refreshing; +@property(nonatomic, strong) void (^onRefreshBlock)(void); +@property(nonatomic, weak) id swipePullingDelegate; +@end \ No newline at end of file diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m new file mode 100644 index 00000000..bc6f28a0 --- /dev/null +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m @@ -0,0 +1,118 @@ +// +// Created by pengfei.zhou on 2019/11/26. +// + +#import "DoricSwipeRefreshLayout.h" +#import "UIView+Doric.h" +#import "DoricLayouts.h" +#import "Doric.h" + +@interface DoricSwipeRefreshLayout () + +@end + +@implementation DoricSwipeRefreshLayout + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + self.showsHorizontalScrollIndicator = NO; + self.showsVerticalScrollIndicator = NO; + self.delegate = self; + } + return self; +} + +- (instancetype)init { + if (self = [super init]) { + self.showsHorizontalScrollIndicator = NO; + self.showsVerticalScrollIndicator = NO; + self.delegate = self; + } + return self; +} + +- (CGSize)sizeThatFits:(CGSize)size { + if (self.contentView) { + CGSize childSize = [self.contentView sizeThatFits:size]; + return CGSizeMake(MIN(size.width, childSize.width), MIN(size.height, childSize.height)); + } + return CGSizeZero; +} + +- (void)setContentView:(UIView *)contentView { + if (_contentView) { + [_contentView removeFromSuperview]; + } + _contentView = contentView; + [self addSubview:contentView]; +} + +- (void)setHeaderView:(UIView *)headerView { + if (_headerView) { + [_headerView removeFromSuperview]; + } + _headerView = headerView; + [self addSubview:headerView]; + self.refreshable = YES; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + [self layoutSelf]; + [self.contentView also:^(UIView *it) { + [it layoutSubviews]; + it.x = it.y = 0; + }]; + [self.headerView also:^(UIView *it) { + [it layoutSubviews]; + it.bottom = it.centerX = 0; + }]; + self.contentSize = self.frame.size; +} + +- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { + if (-scrollView.contentOffset.y >= self.headerView.height) { + self.refreshing = YES; + } +} + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + if (scrollView.contentOffset.y <= 0) { + [self.swipePullingDelegate setProgressRotation:-scrollView.contentOffset.y / self.headerView.height]; + } +} + +- (void)setRefreshing:(BOOL)refreshing { + if (_refreshing == refreshing) { + return; + } + if (refreshing) { + [UIView animateWithDuration:0.3f + animations:^{ + self.contentInset = UIEdgeInsetsMake(self.headerView.height, 0, 0, 0); + } + completion:^(BOOL finished) { + [self.swipePullingDelegate startAnimation]; + } + ]; + } else { + [UIView animateWithDuration:0.3f + animations:^{ + self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); + } + completion:^(BOOL finished) { + [self.swipePullingDelegate stopAnimation]; + } + ]; + } + _refreshing = refreshing; +} + +- (void)setRefreshable:(BOOL)refreshable { + self.scrollEnabled = refreshable; +} + +- (BOOL)refreshable { + return self.scrollEnabled; +} +@end diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.h b/iOS/Pod/Classes/Shader/DoricLayouts.h index 33c3ea86..375435eb 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.h +++ b/iOS/Pod/Classes/Shader/DoricLayouts.h @@ -94,4 +94,8 @@ typedef NS_ENUM(NSInteger, DoricGravity) { @property(nonatomic, copy) NSString *tagString; - (UIView *)viewWithTagString:(NSString *)tagString; + +- (CGSize)targetLayoutSize; + +- (void)layoutSelf; @end diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index bf238368..776a2802 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -70,7 +70,7 @@ - (void)layoutSubviews { if ([self.superview isKindOfClass:[DoricLayoutContainer class]]) { [self.superview layoutSubviews]; } else { - CGSize size = [self sizeThatFits:CGSizeMake(self.superview.width, self.superview.height)]; + CGSize size = [self sizeThatFits:self.targetLayoutSize]; [self layout:size]; } } @@ -160,6 +160,8 @@ - (CGSize)sizeContent:(CGSize)size { } - (void)layout:(CGSize)targetSize { + self.width = targetSize.width; + self.height = targetSize.height; for (UIView *child in self.subviews) { if (child.isHidden) { continue; @@ -223,8 +225,6 @@ - (void)layout:(CGSize)targetSize { [(DoricLayoutContainer *) child layout:size]; } } - self.width = targetSize.width; - self.height = targetSize.height; } @end @@ -278,6 +278,8 @@ - (CGSize)sizeContent:(CGSize)size { } - (void)layout:(CGSize)targetSize { + self.width = targetSize.width; + self.height = targetSize.height; CGFloat yStart = 0; if ((self.gravity & TOP) == TOP) { yStart = 0; @@ -350,8 +352,6 @@ - (void)layout:(CGSize)targetSize { [(DoricLayoutContainer *) child layout:size]; } } - self.width = targetSize.width; - self.height = targetSize.height; } @end @@ -403,6 +403,8 @@ - (CGSize)sizeContent:(CGSize)size { } - (void)layout:(CGSize)targetSize { + self.width = targetSize.width; + self.height = targetSize.height; CGFloat xStart = 0; if (self.contentWeight) { xStart = 0; @@ -477,8 +479,6 @@ - (void)layout:(CGSize)targetSize { [(DoricLayoutContainer *) child layout:size]; } } - self.width = targetSize.width; - self.height = targetSize.height; } @end @@ -511,6 +511,33 @@ - (UIView *)viewWithTagString:(NSString *)tagString { return [self viewWithTag:[tagString hash]]; } +- (CGSize)targetLayoutSize { + CGFloat width = self.width; + CGFloat height = self.height; + if (self.layoutConfig.widthSpec == DoricLayoutAtMost + || self.layoutConfig.widthSpec == DoricLayoutWrapContent) { + width = self.superview.width; + } + if (self.layoutConfig.heightSpec == DoricLayoutAtMost + || self.layoutConfig.widthSpec == DoricLayoutWrapContent) { + height = self.superview.height; + } + return CGSizeMake(width, height); +} + +- (void)layoutSelf { + CGSize contentSize = [self sizeThatFits:self.targetLayoutSize]; + if (self.layoutConfig.widthSpec == DoricLayoutAtMost) { + self.width = self.superview.width; + } else if (self.layoutConfig.widthSpec == DoricLayoutWrapContent) { + self.width = contentSize.width; + } + if (self.layoutConfig.heightSpec == DoricLayoutAtMost) { + self.height = self.superview.height; + } else if (self.layoutConfig.heightSpec == DoricLayoutWrapContent) { + self.height = contentSize.height; + } +} @end DoricVLayoutView *vLayout(NSArray <__kindof UIView *> *views) { diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.h b/iOS/Pod/Classes/Shader/DoricScrollerNode.h index c1184e41..ec8a2253 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.h +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.h @@ -22,5 +22,9 @@ #import #import "DoricSuperNode.h" -@interface DoricScrollerNode : DoricSuperNode +@interface DoricScrollView : UIScrollView +@property(nonatomic, strong) UIView *contentView; +@end + +@interface DoricScrollerNode : DoricSuperNode @end \ No newline at end of file diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.m b/iOS/Pod/Classes/Shader/DoricScrollerNode.m index c492e560..3cf29c4a 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -22,19 +22,25 @@ #import "DoricScrollerNode.h" #import "DoricExtensions.h" -@interface DoricScrollView : UIScrollView -@end - @implementation DoricScrollView +- (void)setContentView:(UIView *)contentView { + if (_contentView) { + [_contentView removeFromSuperview]; + } + _contentView = contentView; + [self addSubview:contentView]; +} + - (void)layoutSubviews { [super layoutSubviews]; + [self layoutSelf]; + [self.contentView layoutSubviews]; } - (CGSize)sizeThatFits:(CGSize)size { - if (self.subviews.count > 0) { - UIView *child = self.subviews[0]; - CGSize childSize = [child sizeThatFits:size]; + if (self.contentView) { + CGSize childSize = [self.contentView sizeThatFits:size]; return CGSizeMake(MIN(size.width, childSize.width), MIN(size.height, childSize.height)); } return CGSizeZero; @@ -47,7 +53,7 @@ @interface DoricScrollerNode () @end @implementation DoricScrollerNode -- (UIScrollView *)build { +- (DoricScrollView *)build { return [DoricScrollView new]; } @@ -70,12 +76,11 @@ - (void)blend:(NSDictionary *)props { [it blend:childProps]; }]; } else { - [self.childNode.view removeFromSuperview]; self.childNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) { it.viewId = viewId; [it initWithSuperNode:self]; [it blend:childProps]; - [self.view addSubview:it.view]; + self.view.contentView = it.view; }]; } } @@ -84,13 +89,12 @@ - (void)blend:(NSDictionary *)props { it.viewId = viewId; [it initWithSuperNode:self]; [it blend:childProps]; - [self.view addSubview:it.view]; + self.view.contentView = it.view; }]; } - [self.view also:^(UIScrollView *it) { - if (it.subviews.count > 0) { - UIView *child = it.subviews[0]; - CGSize size = [child sizeThatFits:it.frame.size]; + [self.view also:^(DoricScrollView *it) { + if (it.contentView) { + CGSize size = [it.contentView sizeThatFits:it.frame.size]; [it setContentSize:size]; } }]; From 2fbf4602e839e21db1b922375d11db3353f4b8ad Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Tue, 26 Nov 2019 21:25:23 +0800 Subject: [PATCH 18/35] feat:add SwipeLayout --- .../Classes/Refresh/DoricRefreshableNode.m | 13 ++++++++++ .../Classes/Refresh/DoricSwipeRefreshLayout.m | 16 +++++------- iOS/Pod/Classes/Shader/DoricLayouts.m | 8 ++++++ iOS/Pod/Classes/Shader/DoricScrollerNode.m | 26 +++++++++---------- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m index 3406fcb1..1b9c3c90 100644 --- a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m +++ b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m @@ -48,6 +48,19 @@ - (void)blend:(NSDictionary *)props { [super blend:props]; [self blendHeader]; [self blendContent]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self.view also:^(DoricSwipeRefreshLayout *layout) { + [layout layoutSelf]; + [layout.contentView also:^(UIView *it) { + it.x = it.y = 0; + }]; + [layout.headerView also:^(UIView *it) { + it.bottom = 0; + it.centerX = layout.width / 2; + }]; + layout.contentSize = layout.frame.size; + }]; + }); } - (void)blendContent { diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m index bc6f28a0..868be55b 100644 --- a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m @@ -17,6 +17,7 @@ - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.showsHorizontalScrollIndicator = NO; self.showsVerticalScrollIndicator = NO; + self.alwaysBounceVertical = YES; self.delegate = self; } return self; @@ -26,6 +27,7 @@ - (instancetype)init { if (self = [super init]) { self.showsHorizontalScrollIndicator = NO; self.showsVerticalScrollIndicator = NO; + self.alwaysBounceVertical = YES; self.delegate = self; } return self; @@ -58,16 +60,6 @@ - (void)setHeaderView:(UIView *)headerView { - (void)layoutSubviews { [super layoutSubviews]; - [self layoutSelf]; - [self.contentView also:^(UIView *it) { - [it layoutSubviews]; - it.x = it.y = 0; - }]; - [self.headerView also:^(UIView *it) { - [it layoutSubviews]; - it.bottom = it.centerX = 0; - }]; - self.contentSize = self.frame.size; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { @@ -115,4 +107,8 @@ - (void)setRefreshable:(BOOL)refreshable { - (BOOL)refreshable { return self.scrollEnabled; } + +- (void)setContentSize:(CGSize)contentSize { + [super setContentSize:contentSize]; +} @end diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index 776a2802..53bf0d7b 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -20,6 +20,7 @@ #import "DoricLayouts.h" #import #import "UIView+Doric.h" +#import "Doric.h" DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom) { DoricMargin margin; @@ -537,6 +538,13 @@ - (void)layoutSelf { } else if (self.layoutConfig.heightSpec == DoricLayoutWrapContent) { self.height = contentSize.height; } + [self.subviews forEach:^(__kindof UIView *obj) { + if ([obj isKindOfClass:[DoricLayoutContainer class]]) { + [obj layoutSubviews]; + } else { + [obj layoutSelf]; + } + }]; } @end diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.m b/iOS/Pod/Classes/Shader/DoricScrollerNode.m index 3cf29c4a..d053566e 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -32,12 +32,6 @@ - (void)setContentView:(UIView *)contentView { [self addSubview:contentView]; } -- (void)layoutSubviews { - [super layoutSubviews]; - [self layoutSelf]; - [self.contentView layoutSubviews]; -} - - (CGSize)sizeThatFits:(CGSize)size { if (self.contentView) { CGSize childSize = [self.contentView sizeThatFits:size]; @@ -92,15 +86,19 @@ - (void)blend:(NSDictionary *)props { self.view.contentView = it.view; }]; } - [self.view also:^(DoricScrollView *it) { - if (it.contentView) { - CGSize size = [it.contentView sizeThatFits:it.frame.size]; - [it setContentSize:size]; - } - }]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self.view also:^(DoricScrollView *it) { + [it layoutSelf]; + if (it.contentView) { + CGSize size = [it.contentView sizeThatFits:it.frame.size]; + [it setContentSize:size]; + } + [it layoutSelf]; + }]; + }); } -- (void)blendView:(UIScrollView *)view forPropName:(NSString *)name propValue:(id)prop { +- (void)blendView:(DoricScrollView *)view forPropName:(NSString *)name propValue:(id)prop { if ([@"content" isEqualToString:name]) { self.childViewId = prop; } else { @@ -111,4 +109,4 @@ - (void)blendView:(UIScrollView *)view forPropName:(NSString *)name propValue:(i - (void)blendSubNode:(NSDictionary *)subModel { [self.childNode blend:subModel[@"props"]]; } -@end \ No newline at end of file +@end From 3c04e7cde1d53bfa74893407075c10940ae68467 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 10:19:25 +0800 Subject: [PATCH 19/35] feat:add Rotation for iOS --- iOS/Pod/Classes/Plugin/DoricShaderPlugin.m | 12 +++++++----- iOS/Pod/Classes/Shader/DoricScrollerNode.m | 7 +++++++ iOS/Pod/Classes/Shader/DoricSuperNode.m | 4 +++- iOS/Pod/Classes/Shader/DoricViewNode.m | 10 ++++++++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/iOS/Pod/Classes/Plugin/DoricShaderPlugin.m b/iOS/Pod/Classes/Plugin/DoricShaderPlugin.m index 32949326..94ff77e7 100644 --- a/iOS/Pod/Classes/Plugin/DoricShaderPlugin.m +++ b/iOS/Pod/Classes/Plugin/DoricShaderPlugin.m @@ -25,8 +25,6 @@ #import "DoricUtil.h" #import "Doric.h" -#import - #import @implementation DoricShaderPlugin @@ -110,9 +108,13 @@ - (id)findClass:(Class)clz target:(id)target method:(NSString *)name promise:(Do dispatch_async(dispatch_get_main_queue(), ^{ void *retValue; block(); - [invocation getReturnValue:&retValue]; - id returnValue = (__bridge id) retValue; - [promise resolve:returnValue]; + const char *retType = methodSignature.methodReturnType; + if (!strcmp(retType, @encode(void))) { + } else { + [invocation getReturnValue:&retValue]; + id returnValue = (__bridge id) retValue; + [promise resolve:returnValue]; + } }); return ret; } diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.m b/iOS/Pod/Classes/Shader/DoricScrollerNode.m index d053566e..087ae15d 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -109,4 +109,11 @@ - (void)blendView:(DoricScrollView *)view forPropName:(NSString *)name propValue - (void)blendSubNode:(NSDictionary *)subModel { [self.childNode blend:subModel[@"props"]]; } + +- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId { + if ([viewId isEqualToString:self.childViewId]) { + return self.childNode; + } + return nil; +} @end diff --git a/iOS/Pod/Classes/Shader/DoricSuperNode.m b/iOS/Pod/Classes/Shader/DoricSuperNode.m index ffcd08ea..232722b4 100644 --- a/iOS/Pod/Classes/Shader/DoricSuperNode.m +++ b/iOS/Pod/Classes/Shader/DoricSuperNode.m @@ -150,9 +150,11 @@ - (void)clearSubModel { } - (DoricViewNode *)subNodeWithViewId:(NSString *)viewId { + NSAssert(NO, @"Should override class:%@ ,method:%@.", NSStringFromClass([self class]), + NSStringFromSelector(_cmd)); return nil; } - (void)requestLayout { [self.view setNeedsLayout]; } -@end \ No newline at end of file +@end diff --git a/iOS/Pod/Classes/Shader/DoricViewNode.m b/iOS/Pod/Classes/Shader/DoricViewNode.m index 1b948504..ce773dbe 100644 --- a/iOS/Pod/Classes/Shader/DoricViewNode.m +++ b/iOS/Pod/Classes/Shader/DoricViewNode.m @@ -232,4 +232,14 @@ - (NSNumber *)getHeight { return @(self.view.height); } +- (void)setRotation:(NSNumber *)rotation { + self.view.transform = CGAffineTransformRotate(self.view.transform, M_PI * rotation.floatValue * 2); +} + +- (NSNumber *)getRotation { + float radius = atan2f((float) self.view.transform.b, (float) self.view.transform.a); + float degree = (float) (radius / M_PI / 2); + return @(degree); +} + @end From a41036c91dd69b02c131497558356dfa3f7c53bc Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 11:55:49 +0800 Subject: [PATCH 20/35] feat:fix transform and layoutcontainer conflict --- demo/src/ListDemo.ts | 1 - demo/src/RefreshableDemo.ts | 27 ++-- demo/src/utils.ts | 4 +- .../Classes/Refresh/DoricRefreshableNode.m | 20 ++- iOS/Pod/Classes/Shader/DoricLayouts.m | 125 +++++++++++------- iOS/Pod/Classes/Shader/DoricViewNode.m | 6 +- js-framework/src/ui/refreshable.ts | 1 - 7 files changed, 113 insertions(+), 71 deletions(-) diff --git a/demo/src/ListDemo.ts b/demo/src/ListDemo.ts index b3de5c46..9c037881 100644 --- a/demo/src/ListDemo.ts +++ b/demo/src/ListDemo.ts @@ -1,6 +1,5 @@ import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text, refreshable, Refreshable, ListItem } from "doric"; import { rotatedArrow, colors } from "./utils"; -import { isObject } from "util"; @Entry class ListPanel extends Panel { build(rootView: Group): void { diff --git a/demo/src/RefreshableDemo.ts b/demo/src/RefreshableDemo.ts index 743da1e6..211108be 100644 --- a/demo/src/RefreshableDemo.ts +++ b/demo/src/RefreshableDemo.ts @@ -20,18 +20,21 @@ class RefreshableDemo extends Panel { width: 30, height: 30, imageBase64: icon_refresh, - }).also(v => refreshImage = v), - ]), { - startAnimation: () => { - log('startAnimation') - }, - stopAnimation: () => { - log('stopAnimation') - }, - setProgressRotation: (rotation: number) => { - refreshImage.setRotation(context, rotation) - }, - }), + }).also(v => { + refreshImage = v + }), + ]), + { + startAnimation: () => { + log('startAnimation') + }, + stopAnimation: () => { + log('stopAnimation') + }, + setProgressRotation: (rotation: number) => { + refreshImage.setRotation(context, rotation) + }, + }), content: scroller(vlayout([ title("Refreshable Demo"), label('start Refresh').apply({ diff --git a/demo/src/utils.ts b/demo/src/utils.ts index 8bb513b6..385cef4c 100644 --- a/demo/src/utils.ts +++ b/demo/src/utils.ts @@ -1,6 +1,4 @@ -import { Color, text, Stack, Text, layoutConfig, LayoutSpec, gravity, pullable, stack, image, Image, BridgeContext } from "doric"; -import { log } from "util"; - +import { Color, text, Stack, Text, layoutConfig, LayoutSpec, gravity, pullable, stack, image, Image, BridgeContext, log } from "doric"; export const icon_refresh = 'data:image/png;base64,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' export const colors = [ diff --git a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m index 1b9c3c90..37f999d6 100644 --- a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m +++ b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m @@ -5,7 +5,7 @@ #import "DoricRefreshableNode.h" #import "Doric.h" -@interface DoricRefreshableNode () +@interface DoricRefreshableNode () @property(nonatomic, strong) DoricViewNode *contentNode; @property(nonatomic, copy) NSString *contentViewId; @property(nonatomic, strong) DoricViewNode *headerNode; @@ -14,7 +14,10 @@ @interface DoricRefreshableNode () @implementation DoricRefreshableNode - (DoricSwipeRefreshLayout *)build { - return [DoricSwipeRefreshLayout new]; + return [[DoricSwipeRefreshLayout new] also:^(DoricSwipeRefreshLayout *it) { + it.swipePullingDelegate = self; + + }]; } - (void)blendView:(DoricSwipeRefreshLayout *)view forPropName:(NSString *)name propValue:(id)prop { @@ -138,4 +141,17 @@ - (void)blendHeader { - (void)blendSubNode:(NSDictionary *)subModel { [[self subNodeWithViewId:subModel[@"id"]] blend:subModel[@"props"]]; } + +- (void)startAnimation { + [self.headerNode callJSResponse:@"startAnimation", nil]; +} + +- (void)stopAnimation { + [self.headerNode callJSResponse:@"stopAnimation", nil]; +} + +- (void)setProgressRotation:(CGFloat)rotation { + [self.headerNode callJSResponse:@"setProgressRotation", @(rotation), nil]; +} + @end diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index 53bf0d7b..7c9f4229 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -129,28 +129,33 @@ - (CGSize)sizeContent:(CGSize)size { if (child.isHidden) { continue; } + DoricLayoutConfig *childConfig = child.layoutConfig; if (!childConfig) { childConfig = [DoricLayoutConfig new]; } CGSize childSize = CGSizeMake(child.width, child.height); - if ([child isKindOfClass:[DoricLayoutContainer class]] - || childConfig.widthSpec == DoricLayoutWrapContent - || childConfig.heightSpec == DoricLayoutWrapContent) { - childSize = [child sizeThatFits:CGSizeMake(size.width, size.height - contentHeight)]; - } - if (childConfig.widthSpec == DoricLayoutExact) { - childSize.width = child.width; - } else if (childConfig.widthSpec == DoricLayoutAtMost) { - childSize.width = size.width; - } - if (childConfig.heightSpec == DoricLayoutExact) { - childSize.height = child.height; - } else if (childConfig.heightSpec == DoricLayoutAtMost) { - childSize.height = size.height - contentHeight; - } - if (childConfig.weight) { - childSize.height = child.height; + if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { + if ([child isKindOfClass:[DoricLayoutContainer class]] + || childConfig.widthSpec == DoricLayoutWrapContent + || childConfig.heightSpec == DoricLayoutWrapContent) { + childSize = [child sizeThatFits:CGSizeMake(size.width, size.height - contentHeight)]; + } + if (childConfig.widthSpec == DoricLayoutExact) { + childSize.width = child.width; + } else if (childConfig.widthSpec == DoricLayoutAtMost) { + childSize.width = size.width; + } + if (childConfig.heightSpec == DoricLayoutExact) { + childSize.height = child.height; + } else if (childConfig.heightSpec == DoricLayoutAtMost) { + childSize.height = size.height - contentHeight; + } + if (childConfig.weight) { + childSize.height = child.height; + } + } else { + childSize = child.bounds.size; } contentWidth = MAX(contentWidth, childSize.width + childConfig.margin.left + childConfig.margin.right); contentHeight = MAX(contentHeight, childSize.height + childConfig.margin.top + childConfig.margin.bottom); @@ -167,6 +172,9 @@ - (void)layout:(CGSize)targetSize { if (child.isHidden) { continue; } + if (!CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { + continue; + } DoricLayoutConfig *childConfig = child.layoutConfig; if (!childConfig) { childConfig = [DoricLayoutConfig new]; @@ -246,23 +254,27 @@ - (CGSize)sizeContent:(CGSize)size { childConfig = [DoricLayoutConfig new]; } CGSize childSize = CGSizeMake(child.width, child.height); - if ([child isKindOfClass:[DoricLayoutContainer class]] - || childConfig.widthSpec == DoricLayoutWrapContent - || childConfig.heightSpec == DoricLayoutWrapContent) { - childSize = [child sizeThatFits:CGSizeMake(size.width, size.height - contentHeight)]; - } - if (childConfig.widthSpec == DoricLayoutExact) { - childSize.width = child.width; - } else if (childConfig.widthSpec == DoricLayoutAtMost) { - childSize.width = size.width; - } - if (childConfig.heightSpec == DoricLayoutExact) { - childSize.height = child.height; - } else if (childConfig.heightSpec == DoricLayoutAtMost) { - childSize.height = size.height - contentHeight; - } - if (childConfig.weight) { - childSize.height = child.height; + if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { + if ([child isKindOfClass:[DoricLayoutContainer class]] + || childConfig.widthSpec == DoricLayoutWrapContent + || childConfig.heightSpec == DoricLayoutWrapContent) { + childSize = [child sizeThatFits:CGSizeMake(size.width, size.height - contentHeight)]; + } + if (childConfig.widthSpec == DoricLayoutExact) { + childSize.width = child.width; + } else if (childConfig.widthSpec == DoricLayoutAtMost) { + childSize.width = size.width; + } + if (childConfig.heightSpec == DoricLayoutExact) { + childSize.height = child.height; + } else if (childConfig.heightSpec == DoricLayoutAtMost) { + childSize.height = size.height - contentHeight; + } + if (childConfig.weight) { + childSize.height = child.height; + } + } else { + childSize = child.bounds.size; } contentWidth = MAX(contentWidth, childSize.width + childConfig.margin.left + childConfig.margin.right); contentHeight += childSize.height + self.space + childConfig.margin.top + childConfig.margin.bottom; @@ -294,6 +306,9 @@ - (void)layout:(CGSize)targetSize { if (child.isHidden) { continue; } + if (!CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { + continue; + } DoricLayoutConfig *childConfig = child.layoutConfig; if (!childConfig) { childConfig = [DoricLayoutConfig new]; @@ -371,24 +386,29 @@ - (CGSize)sizeContent:(CGSize)size { childConfig = [DoricLayoutConfig new]; } CGSize childSize = CGSizeMake(child.width, child.height); - if ([child isKindOfClass:[DoricLayoutContainer class]] - || childConfig.widthSpec == DoricLayoutWrapContent - || childConfig.heightSpec == DoricLayoutWrapContent) { - childSize = [child sizeThatFits:CGSizeMake(size.width - contentWidth, size.height)]; - } - if (childConfig.widthSpec == DoricLayoutExact) { - childSize.width = child.width; - } else if (childConfig.widthSpec == DoricLayoutAtMost) { - childSize.width = size.width - contentWidth; - } - if (childConfig.heightSpec == DoricLayoutExact) { - childSize.height = child.height; - } else if (childConfig.heightSpec == DoricLayoutAtMost) { - childSize.height = size.height; - } - if (childConfig.weight) { - childSize.width = child.width; + if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { + if ([child isKindOfClass:[DoricLayoutContainer class]] + || childConfig.widthSpec == DoricLayoutWrapContent + || childConfig.heightSpec == DoricLayoutWrapContent) { + childSize = [child sizeThatFits:CGSizeMake(size.width - contentWidth, size.height)]; + } + if (childConfig.widthSpec == DoricLayoutExact) { + childSize.width = child.width; + } else if (childConfig.widthSpec == DoricLayoutAtMost) { + childSize.width = size.width - contentWidth; + } + if (childConfig.heightSpec == DoricLayoutExact) { + childSize.height = child.height; + } else if (childConfig.heightSpec == DoricLayoutAtMost) { + childSize.height = size.height; + } + if (childConfig.weight) { + childSize.width = child.width; + } + } else { + childSize = child.bounds.size; } + contentWidth += childSize.width + self.space + childConfig.margin.left + childConfig.margin.right; contentHeight = MAX(contentHeight, childSize.height + childConfig.margin.top + childConfig.margin.bottom); contentWeight += childConfig.weight; @@ -421,6 +441,9 @@ - (void)layout:(CGSize)targetSize { if (child.isHidden) { continue; } + if (!CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { + continue; + } DoricLayoutConfig *childConfig = child.layoutConfig; if (!childConfig) { childConfig = [DoricLayoutConfig new]; diff --git a/iOS/Pod/Classes/Shader/DoricViewNode.m b/iOS/Pod/Classes/Shader/DoricViewNode.m index ce773dbe..3a432cbb 100644 --- a/iOS/Pod/Classes/Shader/DoricViewNode.m +++ b/iOS/Pod/Classes/Shader/DoricViewNode.m @@ -233,7 +233,11 @@ - (NSNumber *)getHeight { } - (void)setRotation:(NSNumber *)rotation { - self.view.transform = CGAffineTransformRotate(self.view.transform, M_PI * rotation.floatValue * 2); + if (rotation.floatValue == 0) { + self.view.transform = CGAffineTransformIdentity; + } else { + self.view.transform = CGAffineTransformMakeRotation(M_PI * rotation.floatValue * 2); + } } - (NSNumber *)getRotation { diff --git a/js-framework/src/ui/refreshable.ts b/js-framework/src/ui/refreshable.ts index 35de57d7..556196e3 100644 --- a/js-framework/src/ui/refreshable.ts +++ b/js-framework/src/ui/refreshable.ts @@ -3,7 +3,6 @@ import { List } from "./list"; import { Scroller } from "./scroller"; import { BridgeContext } from "../runtime/global"; import { layoutConfig } from "./declarative"; -import { Image } from "./widgets"; export interface IRefreshable extends IView { content: List | Scroller From 9be891e2848dd187d6ee23702236ed4d20dfa828 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 13:30:31 +0800 Subject: [PATCH 21/35] feat:fix Refreshable pulldown and so on --- iOS/Pod/Classes/Doric.h | 3 ++- iOS/Pod/Classes/Refresh/DoricRefreshableNode.m | 17 +++++++++++++++++ .../Classes/Refresh/DoricSwipeRefreshLayout.m | 3 +++ iOS/Pod/Classes/Shader/DoricLayouts.m | 2 +- iOS/Pod/Classes/Shader/DoricListNode.m | 7 ++++++- iOS/Pod/Classes/Shader/DoricSliderNode.m | 2 ++ 6 files changed, 31 insertions(+), 3 deletions(-) diff --git a/iOS/Pod/Classes/Doric.h b/iOS/Pod/Classes/Doric.h index 1b6471d2..e96c2565 100644 --- a/iOS/Pod/Classes/Doric.h +++ b/iOS/Pod/Classes/Doric.h @@ -24,4 +24,5 @@ #import "DoricJSLoaderManager.h" #import "DoricNavigatorDelegate.h" #import "DoricNavBarDelegate.h" -#import "DoricViewController.h" \ No newline at end of file +#import "DoricViewController.h" +#import "DoricPromise.h" \ No newline at end of file diff --git a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m index 37f999d6..df6de98c 100644 --- a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m +++ b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m @@ -154,4 +154,21 @@ - (void)setProgressRotation:(CGFloat)rotation { [self.headerNode callJSResponse:@"setProgressRotation", @(rotation), nil]; } +- (void)setRefreshing:(NSNumber *)refreshable withPromise:(DoricPromise *)promise { + self.view.refreshing = [refreshable boolValue]; + [promise resolve:nil]; +} + +- (void)setRefreshable:(NSNumber *)refreshing withPromise:(DoricPromise *)promise { + self.view.refreshable = [refreshing boolValue]; + [promise resolve:nil]; +} + +- (NSNumber *)isRefreshing { + return @(self.view.refreshing); +} + +- (NSNumber *)isRefreshable { + return @(self.view.refreshable); +} @end diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m index 868be55b..84d3b6d6 100644 --- a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m @@ -79,6 +79,9 @@ - (void)setRefreshing:(BOOL)refreshing { return; } if (refreshing) { + if (self.onRefreshBlock) { + self.onRefreshBlock(); + } [UIView animateWithDuration:0.3f animations:^{ self.contentInset = UIEdgeInsetsMake(self.headerView.height, 0, 0, 0); diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index 7c9f4229..13e82999 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -543,7 +543,7 @@ - (CGSize)targetLayoutSize { width = self.superview.width; } if (self.layoutConfig.heightSpec == DoricLayoutAtMost - || self.layoutConfig.widthSpec == DoricLayoutWrapContent) { + || self.layoutConfig.heightSpec == DoricLayoutWrapContent) { height = self.superview.height; } return CGSizeMake(width, height); diff --git a/iOS/Pod/Classes/Shader/DoricListNode.m b/iOS/Pod/Classes/Shader/DoricListNode.m index b1aa6eb4..4625e6a6 100644 --- a/iOS/Pod/Classes/Shader/DoricListNode.m +++ b/iOS/Pod/Classes/Shader/DoricListNode.m @@ -36,10 +36,13 @@ @implementation DoricTableView - (CGSize)sizeThatFits:(CGSize)size { if (self.subviews.count > 0) { CGFloat width = size.width; + CGFloat height = 0; + for (UIView *child in self.subviews) { width = MAX(child.width, width); + height += child.height; } - return CGSizeMake(width, size.width); + return CGSizeMake(width, height); } return size; } @@ -74,9 +77,11 @@ - (UITableView *)build { - (void)blendView:(UITableView *)view forPropName:(NSString *)name propValue:(id)prop { if ([@"itemCount" isEqualToString:name]) { self.itemCount = [prop unsignedIntegerValue]; + [self.view reloadData]; } else if ([@"renderItem" isEqualToString:name]) { [self.itemViewIds removeAllObjects]; [self clearSubModel]; + [self.view reloadData]; } else if ([@"batchCount" isEqualToString:name]) { self.batchCount = [prop unsignedIntegerValue]; } else { diff --git a/iOS/Pod/Classes/Shader/DoricSliderNode.m b/iOS/Pod/Classes/Shader/DoricSliderNode.m index e409dcd4..de74db8b 100644 --- a/iOS/Pod/Classes/Shader/DoricSliderNode.m +++ b/iOS/Pod/Classes/Shader/DoricSliderNode.m @@ -80,9 +80,11 @@ - (UICollectionView *)build { - (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValue:(id)prop { if ([@"itemCount" isEqualToString:name]) { self.itemCount = [prop unsignedIntegerValue]; + [self.view reloadData]; } else if ([@"renderPage" isEqualToString:name]) { [self.itemViewIds removeAllObjects]; [self clearSubModel]; + [self.view reloadData]; } else if ([@"batchCount" isEqualToString:name]) { self.batchCount = [prop unsignedIntegerValue]; } else { From fe292f7b7fce8d9f6992d01762c1d5418b7d6b55 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 14:16:55 +0800 Subject: [PATCH 22/35] feat:Prepare to refact DoricLayouts,because it wont be sized corretly for other views like scrollview or tableview --- iOS/Pod/Classes/Shader/DoricLayouts.h | 2 ++ iOS/Pod/Classes/Shader/DoricLayouts.m | 33 +++++++++++++++++++++++--- iOS/Pod/Classes/Shader/DoricListNode.m | 8 ++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.h b/iOS/Pod/Classes/Shader/DoricLayouts.h index 375435eb..c3ac96b7 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.h +++ b/iOS/Pod/Classes/Shader/DoricLayouts.h @@ -98,4 +98,6 @@ typedef NS_ENUM(NSInteger, DoricGravity) { - (CGSize)targetLayoutSize; - (void)layoutSelf; + +- (CGSize)measureSize:(CGSize)targetSize; @end diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index 13e82999..b9a609f0 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -540,17 +540,44 @@ - (CGSize)targetLayoutSize { CGFloat height = self.height; if (self.layoutConfig.widthSpec == DoricLayoutAtMost || self.layoutConfig.widthSpec == DoricLayoutWrapContent) { - width = self.superview.width; + width = self.superview.targetLayoutSize.width; } if (self.layoutConfig.heightSpec == DoricLayoutAtMost || self.layoutConfig.heightSpec == DoricLayoutWrapContent) { - height = self.superview.height; + height = self.superview.targetLayoutSize.height; + } + return CGSizeMake(width, height); +} + +- (CGSize)measureSize:(CGSize)targetSize { + CGFloat width = self.width; + CGFloat height = self.height; + + DoricLayoutConfig *config = self.layoutConfig; + if (!config) { + config = [DoricLayoutConfig new]; + } + if (config.widthSpec == DoricLayoutAtMost + || config.widthSpec == DoricLayoutWrapContent) { + width = targetSize.width - config.margin.left - config.margin.right; + } + if (config.heightSpec == DoricLayoutAtMost + || config.heightSpec == DoricLayoutWrapContent) { + height = targetSize.height - config.margin.top - config.margin.bottom; + } + + CGSize contentSize = [self sizeThatFits:CGSizeMake(width, height)]; + if (config.widthSpec == DoricLayoutWrapContent) { + width = contentSize.width; + } + if (config.heightSpec == DoricLayoutWrapContent) { + height = contentSize.height; } return CGSizeMake(width, height); } - (void)layoutSelf { - CGSize contentSize = [self sizeThatFits:self.targetLayoutSize]; + CGSize contentSize = [self measureSize:self.targetLayoutSize]; if (self.layoutConfig.widthSpec == DoricLayoutAtMost) { self.width = self.superview.width; } else if (self.layoutConfig.widthSpec == DoricLayoutWrapContent) { diff --git a/iOS/Pod/Classes/Shader/DoricListNode.m b/iOS/Pod/Classes/Shader/DoricListNode.m index 4625e6a6..02751c1b 100644 --- a/iOS/Pod/Classes/Shader/DoricListNode.m +++ b/iOS/Pod/Classes/Shader/DoricListNode.m @@ -21,6 +21,7 @@ #import "DoricListNode.h" #import "DoricExtensions.h" #import "DoricListItemNode.h" +#import "DoricLayouts.h" @interface DoricTableViewCell : UITableViewCell @property(nonatomic, strong) DoricListItemNode *doricListItemNode; @@ -39,10 +40,11 @@ - (CGSize)sizeThatFits:(CGSize)size { CGFloat height = 0; for (UIView *child in self.subviews) { - width = MAX(child.width, width); - height += child.height; + CGSize childSize = [child measureSize:size]; + width = MAX(childSize.width, width); + height += childSize.height; } - return CGSizeMake(width, height); + return CGSizeMake(width, MAX(height, size.height)); } return size; } From bb9e6671f662ac61b5acc3c67c2e1d1f4d26b492 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 14:31:52 +0800 Subject: [PATCH 23/35] feat:step1 --- iOS/Pod/Classes/Shader/DoricLayouts.h | 18 +-- iOS/Pod/Classes/Shader/DoricLayouts.m | 197 ++++++++++++++------------ 2 files changed, 113 insertions(+), 102 deletions(-) diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.h b/iOS/Pod/Classes/Shader/DoricLayouts.h index c3ac96b7..f0da117e 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.h +++ b/iOS/Pod/Classes/Shader/DoricLayouts.h @@ -19,14 +19,7 @@ #import - -struct DoricMargin { - CGFloat left; - CGFloat right; - CGFloat top; - CGFloat bottom; -}; -typedef struct DoricMargin DoricMargin; +typedef UIEdgeInsets DoricMargin; DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom); @@ -91,13 +84,16 @@ typedef NS_ENUM(NSInteger, DoricGravity) { @interface UIView (DoricLayoutConfig) @property(nonatomic, strong) DoricLayoutConfig *layoutConfig; +@end + +@interface UIView (DoricTag) @property(nonatomic, copy) NSString *tagString; - (UIView *)viewWithTagString:(NSString *)tagString; +@end -- (CGSize)targetLayoutSize; - +@interface UIView (DoricLayouts) - (void)layoutSelf; - (CGSize)measureSize:(CGSize)targetSize; -@end +@end \ No newline at end of file diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index b9a609f0..1ca0cd9a 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -22,6 +22,108 @@ #import "UIView+Doric.h" #import "Doric.h" +static const void *kLayoutConfig = &kLayoutConfig; + +@implementation UIView (DoricLayoutConfig) +@dynamic layoutConfig; + +- (void)setLayoutConfig:(DoricLayoutConfig *)layoutConfig { + objc_setAssociatedObject(self, kLayoutConfig, layoutConfig, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (DoricLayoutConfig *)layoutConfig { + return objc_getAssociatedObject(self, kLayoutConfig); +} + +@end + +static const void *kTagString = &kTagString; + +@implementation UIView (DoricTag) + +- (void)setTagString:(NSString *)tagString { + objc_setAssociatedObject(self, kTagString, tagString, OBJC_ASSOCIATION_COPY_NONATOMIC); + self.tag = [tagString hash]; +} + +- (NSString *)tagString { + return objc_getAssociatedObject(self, kTagString); +} + + +- (UIView *)viewWithTagString:(NSString *)tagString { + // notice the potential hash collision + return [self viewWithTag:[tagString hash]]; +} + +@end + + +@implementation UIView (DoricLayouts) + +- (CGSize)targetLayoutSize { + CGFloat width = self.width; + CGFloat height = self.height; + if (self.layoutConfig.widthSpec == DoricLayoutAtMost + || self.layoutConfig.widthSpec == DoricLayoutWrapContent) { + width = self.superview.targetLayoutSize.width; + } + if (self.layoutConfig.heightSpec == DoricLayoutAtMost + || self.layoutConfig.heightSpec == DoricLayoutWrapContent) { + height = self.superview.targetLayoutSize.height; + } + return CGSizeMake(width, height); +} + +- (CGSize)measureSize:(CGSize)targetSize { + CGFloat width = self.width; + CGFloat height = self.height; + + DoricLayoutConfig *config = self.layoutConfig; + if (!config) { + config = [DoricLayoutConfig new]; + } + if (config.widthSpec == DoricLayoutAtMost + || config.widthSpec == DoricLayoutWrapContent) { + width = targetSize.width - config.margin.left - config.margin.right; + } + if (config.heightSpec == DoricLayoutAtMost + || config.heightSpec == DoricLayoutWrapContent) { + height = targetSize.height - config.margin.top - config.margin.bottom; + } + + CGSize contentSize = [self sizeThatFits:CGSizeMake(width, height)]; + if (config.widthSpec == DoricLayoutWrapContent) { + width = contentSize.width; + } + if (config.heightSpec == DoricLayoutWrapContent) { + height = contentSize.height; + } + return CGSizeMake(width, height); +} + +- (void)layoutSelf { + CGSize contentSize = [self measureSize:self.targetLayoutSize]; + if (self.layoutConfig.widthSpec == DoricLayoutAtMost) { + self.width = self.superview.width; + } else if (self.layoutConfig.widthSpec == DoricLayoutWrapContent) { + self.width = contentSize.width; + } + if (self.layoutConfig.heightSpec == DoricLayoutAtMost) { + self.height = self.superview.height; + } else if (self.layoutConfig.heightSpec == DoricLayoutWrapContent) { + self.height = contentSize.height; + } + [self.subviews forEach:^(__kindof UIView *obj) { + if ([obj isKindOfClass:[DoricLayoutContainer class]]) { + [obj layoutSubviews]; + } else { + [obj layoutSelf]; + } + }]; +} +@end + DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom) { DoricMargin margin; margin.left = left; @@ -373,6 +475,10 @@ - (void)layout:(CGSize)targetSize { @implementation DoricHLayoutView +- (void)layoutSelf { + [super layoutSelf]; +} + - (CGSize)sizeContent:(CGSize)size { CGFloat contentWidth = 0; CGFloat contentHeight = 0; @@ -506,97 +612,6 @@ - (void)layout:(CGSize)targetSize { } @end -static const void *kLayoutConfig = &kLayoutConfig; -static const void *kTagString = &kTagString; - -@implementation UIView (DoricLayoutConfig) -@dynamic layoutConfig; - -- (void)setLayoutConfig:(DoricLayoutConfig *)layoutConfig { - objc_setAssociatedObject(self, kLayoutConfig, layoutConfig, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (DoricLayoutConfig *)layoutConfig { - return objc_getAssociatedObject(self, kLayoutConfig); -} - -- (void)setTagString:(NSString *)tagString { - objc_setAssociatedObject(self, kTagString, tagString, OBJC_ASSOCIATION_COPY_NONATOMIC); - self.tag = [tagString hash]; -} - -- (NSString *)tagString { - return objc_getAssociatedObject(self, kTagString); -} - - -- (UIView *)viewWithTagString:(NSString *)tagString { - // notice the potential hash collision - return [self viewWithTag:[tagString hash]]; -} - -- (CGSize)targetLayoutSize { - CGFloat width = self.width; - CGFloat height = self.height; - if (self.layoutConfig.widthSpec == DoricLayoutAtMost - || self.layoutConfig.widthSpec == DoricLayoutWrapContent) { - width = self.superview.targetLayoutSize.width; - } - if (self.layoutConfig.heightSpec == DoricLayoutAtMost - || self.layoutConfig.heightSpec == DoricLayoutWrapContent) { - height = self.superview.targetLayoutSize.height; - } - return CGSizeMake(width, height); -} - -- (CGSize)measureSize:(CGSize)targetSize { - CGFloat width = self.width; - CGFloat height = self.height; - - DoricLayoutConfig *config = self.layoutConfig; - if (!config) { - config = [DoricLayoutConfig new]; - } - if (config.widthSpec == DoricLayoutAtMost - || config.widthSpec == DoricLayoutWrapContent) { - width = targetSize.width - config.margin.left - config.margin.right; - } - if (config.heightSpec == DoricLayoutAtMost - || config.heightSpec == DoricLayoutWrapContent) { - height = targetSize.height - config.margin.top - config.margin.bottom; - } - - CGSize contentSize = [self sizeThatFits:CGSizeMake(width, height)]; - if (config.widthSpec == DoricLayoutWrapContent) { - width = contentSize.width; - } - if (config.heightSpec == DoricLayoutWrapContent) { - height = contentSize.height; - } - return CGSizeMake(width, height); -} - -- (void)layoutSelf { - CGSize contentSize = [self measureSize:self.targetLayoutSize]; - if (self.layoutConfig.widthSpec == DoricLayoutAtMost) { - self.width = self.superview.width; - } else if (self.layoutConfig.widthSpec == DoricLayoutWrapContent) { - self.width = contentSize.width; - } - if (self.layoutConfig.heightSpec == DoricLayoutAtMost) { - self.height = self.superview.height; - } else if (self.layoutConfig.heightSpec == DoricLayoutWrapContent) { - self.height = contentSize.height; - } - [self.subviews forEach:^(__kindof UIView *obj) { - if ([obj isKindOfClass:[DoricLayoutContainer class]]) { - [obj layoutSubviews]; - } else { - [obj layoutSelf]; - } - }]; -} -@end DoricVLayoutView *vLayout(NSArray <__kindof UIView *> *views) { DoricVLayoutView *layout = [[DoricVLayoutView alloc] initWithFrame:CGRectZero]; From af8a455d466a5cee1be51afa58ea36e0dabc314c Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 15:28:39 +0800 Subject: [PATCH 24/35] feat:step2 --- .../Classes/Refresh/DoricRefreshableNode.m | 13 - iOS/Pod/Classes/Shader/DoricLayouts.h | 10 +- iOS/Pod/Classes/Shader/DoricLayouts.m | 276 ++++-------------- iOS/Pod/Classes/Shader/DoricScrollerNode.m | 10 - 4 files changed, 58 insertions(+), 251 deletions(-) diff --git a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m index df6de98c..137dc5e2 100644 --- a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m +++ b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m @@ -51,19 +51,6 @@ - (void)blend:(NSDictionary *)props { [super blend:props]; [self blendHeader]; [self blendContent]; - dispatch_async(dispatch_get_main_queue(), ^{ - [self.view also:^(DoricSwipeRefreshLayout *layout) { - [layout layoutSelf]; - [layout.contentView also:^(UIView *it) { - it.x = it.y = 0; - }]; - [layout.headerView also:^(UIView *it) { - it.bottom = 0; - it.centerX = layout.width / 2; - }]; - layout.contentSize = layout.frame.size; - }]; - }); } - (void)blendContent { diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.h b/iOS/Pod/Classes/Shader/DoricLayouts.h index f0da117e..86824f3c 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.h +++ b/iOS/Pod/Classes/Shader/DoricLayouts.h @@ -61,17 +61,13 @@ typedef NS_ENUM(NSInteger, DoricGravity) { @interface DoricLayoutContainer : UIView -@property(nonatomic, assign) DoricGravity gravity; - -- (void)layout:(CGSize)targetSize; - -- (CGSize)sizeContent:(CGSize)size; @end @interface DoricStackView : DoricLayoutContainer @end @interface DoricLinearView : DoricLayoutContainer +@property(nonatomic, assign) DoricGravity gravity; @property(nonatomic, assign) CGFloat space; @end @@ -93,7 +89,9 @@ typedef NS_ENUM(NSInteger, DoricGravity) { @end @interface UIView (DoricLayouts) -- (void)layoutSelf; +- (void)layoutSelf:(CGSize)targetSize; - (CGSize)measureSize:(CGSize)targetSize; + +- (void)doricLayoutSubviews; @end \ No newline at end of file diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index 1ca0cd9a..5ef151f0 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -19,8 +19,8 @@ #import "DoricLayouts.h" #import +#import #import "UIView+Doric.h" -#import "Doric.h" static const void *kLayoutConfig = &kLayoutConfig; @@ -60,21 +60,9 @@ - (UIView *)viewWithTagString:(NSString *)tagString { @implementation UIView (DoricLayouts) - -- (CGSize)targetLayoutSize { - CGFloat width = self.width; - CGFloat height = self.height; - if (self.layoutConfig.widthSpec == DoricLayoutAtMost - || self.layoutConfig.widthSpec == DoricLayoutWrapContent) { - width = self.superview.targetLayoutSize.width; - } - if (self.layoutConfig.heightSpec == DoricLayoutAtMost - || self.layoutConfig.heightSpec == DoricLayoutWrapContent) { - height = self.superview.targetLayoutSize.height; - } - return CGSizeMake(width, height); -} - +/** + * Measure self's size + * */ - (CGSize)measureSize:(CGSize)targetSize { CGFloat width = self.width; CGFloat height = self.height; @@ -102,26 +90,38 @@ - (CGSize)measureSize:(CGSize)targetSize { return CGSizeMake(width, height); } -- (void)layoutSelf { - CGSize contentSize = [self measureSize:self.targetLayoutSize]; +/** + * layout self and subviews + * */ +- (void)layoutSelf:(CGSize)targetSize { + CGSize contentSize = [self measureSize:targetSize]; if (self.layoutConfig.widthSpec == DoricLayoutAtMost) { - self.width = self.superview.width; + self.width = targetSize.width; } else if (self.layoutConfig.widthSpec == DoricLayoutWrapContent) { self.width = contentSize.width; } if (self.layoutConfig.heightSpec == DoricLayoutAtMost) { - self.height = self.superview.height; + self.height = targetSize.height; } else if (self.layoutConfig.heightSpec == DoricLayoutWrapContent) { self.height = contentSize.height; } - [self.subviews forEach:^(__kindof UIView *obj) { - if ([obj isKindOfClass:[DoricLayoutContainer class]]) { - [obj layoutSubviews]; - } else { - [obj layoutSelf]; - } - }]; } + +- (BOOL)requestSuperview { + return self.superview + && self.layoutConfig + && self.layoutConfig.widthSpec != DoricLayoutExact + && self.layoutConfig.heightSpec != DoricLayoutExact; +} + +- (void)doricLayoutSubviews { + if ([self requestSuperview]) { + [self.superview doricLayoutSubviews]; + } else { + [self layoutSelf:CGSizeMake(self.width, self.height)]; + } +} + @end DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom) { @@ -168,94 +168,34 @@ @interface DoricLayoutContainer () @end @implementation DoricLayoutContainer - - (void)layoutSubviews { - if ([self.superview isKindOfClass:[DoricLayoutContainer class]]) { - [self.superview layoutSubviews]; - } else { - CGSize size = [self sizeThatFits:self.targetLayoutSize]; - [self layout:size]; - } -} - -- (CGSize)sizeThatFits:(CGSize)size { - CGFloat width = self.width; - CGFloat height = self.height; - - DoricLayoutConfig *config = self.layoutConfig; - if (!config) { - config = [DoricLayoutConfig new]; - } - if (config.widthSpec == DoricLayoutAtMost - || config.widthSpec == DoricLayoutWrapContent) { - width = size.width - config.margin.left - config.margin.right; - } - if (config.heightSpec == DoricLayoutAtMost - || config.heightSpec == DoricLayoutWrapContent) { - height = size.height - config.margin.top - config.margin.bottom; - } - - CGSize contentSize = [self sizeContent:CGSizeMake(width, height)]; - if (config.widthSpec == DoricLayoutWrapContent) { - width = contentSize.width; - } - if (config.heightSpec == DoricLayoutWrapContent) { - height = contentSize.height; - } - return CGSizeMake(width, height); -} - -- (CGSize)sizeContent:(CGSize)size { - return size; -} - -- (void)layout:(CGSize)targetSize { - self.width = targetSize.width; - self.height = targetSize.height; + [super layoutSubviews]; + [self doricLayoutSubviews]; } @end @interface DoricStackView () - @property(nonatomic, assign) CGFloat contentWidth; @property(nonatomic, assign) CGFloat contentHeight; @end @implementation DoricStackView -- (CGSize)sizeContent:(CGSize)size { +- (CGSize)sizeThatFits:(CGSize)size { CGFloat contentWidth = 0; CGFloat contentHeight = 0; for (UIView *child in self.subviews) { if (child.isHidden) { continue; } - DoricLayoutConfig *childConfig = child.layoutConfig; if (!childConfig) { childConfig = [DoricLayoutConfig new]; } - CGSize childSize = CGSizeMake(child.width, child.height); + CGSize childSize; if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { - if ([child isKindOfClass:[DoricLayoutContainer class]] - || childConfig.widthSpec == DoricLayoutWrapContent - || childConfig.heightSpec == DoricLayoutWrapContent) { - childSize = [child sizeThatFits:CGSizeMake(size.width, size.height - contentHeight)]; - } - if (childConfig.widthSpec == DoricLayoutExact) { - childSize.width = child.width; - } else if (childConfig.widthSpec == DoricLayoutAtMost) { - childSize.width = size.width; - } - if (childConfig.heightSpec == DoricLayoutExact) { - childSize.height = child.height; - } else if (childConfig.heightSpec == DoricLayoutAtMost) { - childSize.height = size.height - contentHeight; - } - if (childConfig.weight) { - childSize.height = child.height; - } + childSize = [child measureSize:CGSizeMake(size.width, size.height)]; } else { childSize = child.bounds.size; } @@ -267,9 +207,8 @@ - (CGSize)sizeContent:(CGSize)size { return CGSizeMake(contentWidth, contentHeight); } -- (void)layout:(CGSize)targetSize { - self.width = targetSize.width; - self.height = targetSize.height; +- (void)layoutSelf:(CGSize)targetSize { + [super layoutSelf:targetSize]; for (UIView *child in self.subviews) { if (child.isHidden) { continue; @@ -281,29 +220,9 @@ - (void)layout:(CGSize)targetSize { if (!childConfig) { childConfig = [DoricLayoutConfig new]; } - - CGSize size = [child sizeThatFits:CGSizeMake(targetSize.width, targetSize.height)]; - if (childConfig.widthSpec == DoricLayoutExact) { - size.width = child.width; - } - if (childConfig.heightSpec == DoricLayoutExact) { - size.height = child.height; - } - if (childConfig.widthSpec == DoricLayoutExact) { - size.width = child.width; - } else if (childConfig.widthSpec == DoricLayoutAtMost) { - size.width = targetSize.width; - } - if (childConfig.heightSpec == DoricLayoutExact) { - size.height = child.height; - } else if (childConfig.heightSpec == DoricLayoutAtMost) { - size.height = targetSize.height; - } - child.width = size.width; - child.height = size.height; - - DoricGravity gravity = childConfig.alignment | self.gravity; - + CGSize size = [child measureSize:CGSizeMake(targetSize.width, targetSize.height)]; + [child layoutSelf:size]; + DoricGravity gravity = childConfig.alignment; if ((gravity & LEFT) == LEFT) { child.left = 0; } else if ((gravity & RIGHT) == RIGHT) { @@ -317,7 +236,6 @@ - (void)layout:(CGSize)targetSize { child.right = targetSize.width - childConfig.margin.right; } } - if ((gravity & TOP) == TOP) { child.top = 0; } else if ((gravity & BOTTOM) == BOTTOM) { @@ -331,10 +249,6 @@ - (void)layout:(CGSize)targetSize { child.bottom = targetSize.height - childConfig.margin.bottom; } } - - if ([child isKindOfClass:[DoricLayoutContainer class]]) { - [(DoricLayoutContainer *) child layout:size]; - } } } @end @@ -343,7 +257,8 @@ @implementation DoricLinearView @end @implementation DoricVLayoutView -- (CGSize)sizeContent:(CGSize)size { + +- (CGSize)sizeThatFits:(CGSize)size { CGFloat contentWidth = 0; CGFloat contentHeight = 0; NSUInteger contentWeight = 0; @@ -355,23 +270,9 @@ - (CGSize)sizeContent:(CGSize)size { if (!childConfig) { childConfig = [DoricLayoutConfig new]; } - CGSize childSize = CGSizeMake(child.width, child.height); + CGSize childSize; if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { - if ([child isKindOfClass:[DoricLayoutContainer class]] - || childConfig.widthSpec == DoricLayoutWrapContent - || childConfig.heightSpec == DoricLayoutWrapContent) { - childSize = [child sizeThatFits:CGSizeMake(size.width, size.height - contentHeight)]; - } - if (childConfig.widthSpec == DoricLayoutExact) { - childSize.width = child.width; - } else if (childConfig.widthSpec == DoricLayoutAtMost) { - childSize.width = size.width; - } - if (childConfig.heightSpec == DoricLayoutExact) { - childSize.height = child.height; - } else if (childConfig.heightSpec == DoricLayoutAtMost) { - childSize.height = size.height - contentHeight; - } + childSize = [child measureSize:CGSizeMake(size.width, size.height - contentHeight)]; if (childConfig.weight) { childSize.height = child.height; } @@ -392,7 +293,8 @@ - (CGSize)sizeContent:(CGSize)size { return CGSizeMake(contentWidth, contentHeight); } -- (void)layout:(CGSize)targetSize { +- (void)layoutSelf:(CGSize)targetSize { + [super layoutSelf:targetSize]; self.width = targetSize.width; self.height = targetSize.height; CGFloat yStart = 0; @@ -416,35 +318,12 @@ - (void)layout:(CGSize)targetSize { childConfig = [DoricLayoutConfig new]; } - CGSize size = [child sizeThatFits:CGSizeMake(targetSize.width, targetSize.height - yStart)]; - if (childConfig.widthSpec == DoricLayoutExact) { - size.width = child.width; - } - if (childConfig.heightSpec == DoricLayoutExact) { - size.height = child.height; - } - if (childConfig.widthSpec == DoricLayoutExact) { - size.width = child.width; - } else if (childConfig.widthSpec == DoricLayoutAtMost) { - size.width = targetSize.width; - } - if (childConfig.heightSpec == DoricLayoutExact) { - size.height = child.height; - } else if (childConfig.heightSpec == DoricLayoutAtMost) { - size.height = targetSize.height - yStart; - } + CGSize size = [child measureSize:CGSizeMake(targetSize.width, targetSize.height - yStart)]; if (childConfig.weight) { - size.height = child.height; + size.height = child.height + remain / self.contentWeight * childConfig.weight; } - - if (childConfig.weight) { - size.height += remain / self.contentWeight * childConfig.weight; - } - child.width = size.width; - child.height = size.height; - + [child layoutSelf:size]; DoricGravity gravity = childConfig.alignment | self.gravity; - if ((gravity & LEFT) == LEFT) { child.left = 0; } else if ((gravity & RIGHT) == RIGHT) { @@ -466,20 +345,12 @@ - (void)layout:(CGSize)targetSize { if (childConfig.margin.bottom) { yStart += childConfig.margin.bottom; } - if ([child isKindOfClass:[DoricLayoutContainer class]]) { - [(DoricLayoutContainer *) child layout:size]; - } } } @end @implementation DoricHLayoutView - -- (void)layoutSelf { - [super layoutSelf]; -} - -- (CGSize)sizeContent:(CGSize)size { +- (CGSize)sizeThatFits:(CGSize)size { CGFloat contentWidth = 0; CGFloat contentHeight = 0; NSUInteger contentWeight = 0; @@ -491,30 +362,15 @@ - (CGSize)sizeContent:(CGSize)size { if (!childConfig) { childConfig = [DoricLayoutConfig new]; } - CGSize childSize = CGSizeMake(child.width, child.height); + CGSize childSize; if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { - if ([child isKindOfClass:[DoricLayoutContainer class]] - || childConfig.widthSpec == DoricLayoutWrapContent - || childConfig.heightSpec == DoricLayoutWrapContent) { - childSize = [child sizeThatFits:CGSizeMake(size.width - contentWidth, size.height)]; - } - if (childConfig.widthSpec == DoricLayoutExact) { - childSize.width = child.width; - } else if (childConfig.widthSpec == DoricLayoutAtMost) { - childSize.width = size.width - contentWidth; - } - if (childConfig.heightSpec == DoricLayoutExact) { - childSize.height = child.height; - } else if (childConfig.heightSpec == DoricLayoutAtMost) { - childSize.height = size.height; - } + childSize = [child measureSize:CGSizeMake(size.width - contentWidth, size.height)]; if (childConfig.weight) { childSize.width = child.width; } } else { childSize = child.bounds.size; } - contentWidth += childSize.width + self.space + childConfig.margin.left + childConfig.margin.right; contentHeight = MAX(contentHeight, childSize.height + childConfig.margin.top + childConfig.margin.bottom); contentWeight += childConfig.weight; @@ -529,9 +385,8 @@ - (CGSize)sizeContent:(CGSize)size { return CGSizeMake(contentWidth, contentHeight); } -- (void)layout:(CGSize)targetSize { - self.width = targetSize.width; - self.height = targetSize.height; +- (void)layoutSelf:(CGSize)targetSize { + [super layoutSelf:targetSize]; CGFloat xStart = 0; if (self.contentWeight) { xStart = 0; @@ -555,32 +410,12 @@ - (void)layout:(CGSize)targetSize { childConfig = [DoricLayoutConfig new]; } - CGSize size = [child sizeThatFits:CGSizeMake(targetSize.width - xStart, targetSize.height)]; - if (childConfig.widthSpec == DoricLayoutExact) { - size.width = child.width; - } - if (childConfig.heightSpec == DoricLayoutExact) { - size.height = child.height; - } - if (childConfig.widthSpec == DoricLayoutExact) { - size.width = child.width; - } else if (childConfig.widthSpec == DoricLayoutAtMost) { - size.width = targetSize.width - xStart; - } - if (childConfig.heightSpec == DoricLayoutExact) { - size.height = child.height; - } else if (childConfig.heightSpec == DoricLayoutAtMost) { - size.height = targetSize.height; - } + CGSize size = [child measureSize:CGSizeMake(targetSize.width - xStart, targetSize.height)]; if (childConfig.weight) { - size.width = child.width; + size.width = child.width + remain / self.contentWeight * childConfig.weight; } - if (childConfig.weight) { - size.width += remain / self.contentWeight * childConfig.weight; - } - child.width = size.width; - child.height = size.height; + [child layoutSelf:size]; DoricGravity gravity = childConfig.alignment | self.gravity; if ((gravity & TOP) == TOP) { @@ -605,9 +440,6 @@ - (void)layout:(CGSize)targetSize { if (childConfig.margin.right) { xStart += childConfig.margin.right; } - if ([child isKindOfClass:[DoricLayoutContainer class]]) { - [(DoricLayoutContainer *) child layout:size]; - } } } @end diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.m b/iOS/Pod/Classes/Shader/DoricScrollerNode.m index 087ae15d..5fb7d0c0 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -86,16 +86,6 @@ - (void)blend:(NSDictionary *)props { self.view.contentView = it.view; }]; } - dispatch_async(dispatch_get_main_queue(), ^{ - [self.view also:^(DoricScrollView *it) { - [it layoutSelf]; - if (it.contentView) { - CGSize size = [it.contentView sizeThatFits:it.frame.size]; - [it setContentSize:size]; - } - [it layoutSelf]; - }]; - }); } - (void)blendView:(DoricScrollView *)view forPropName:(NSString *)name propValue:(id)prop { From 1dabccbe50895f496decade5539f0574643a814a Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 16:04:43 +0800 Subject: [PATCH 25/35] feat:step3:scrollview --- iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m | 11 ++++++----- iOS/Pod/Classes/Shader/DoricLayouts.m | 5 ++--- iOS/Pod/Classes/Shader/DoricListNode.m | 5 +++++ iOS/Pod/Classes/Shader/DoricScrollerNode.m | 9 +++++++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m index 84d3b6d6..f92c0c9f 100644 --- a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m @@ -35,12 +35,16 @@ - (instancetype)init { - (CGSize)sizeThatFits:(CGSize)size { if (self.contentView) { - CGSize childSize = [self.contentView sizeThatFits:size]; - return CGSizeMake(MIN(size.width, childSize.width), MIN(size.height, childSize.height)); + return [self.contentView measureSize:size]; } return CGSizeZero; } +- (void)layoutSelf:(CGSize)targetSize { + [super layoutSelf:targetSize]; + [self.contentView layoutSelf:targetSize]; +} + - (void)setContentView:(UIView *)contentView { if (_contentView) { [_contentView removeFromSuperview]; @@ -58,9 +62,6 @@ - (void)setHeaderView:(UIView *)headerView { self.refreshable = YES; } -- (void)layoutSubviews { - [super layoutSubviews]; -} - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (-scrollView.contentOffset.y >= self.headerView.height) { diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index 5ef151f0..a806496c 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -94,7 +94,7 @@ - (CGSize)measureSize:(CGSize)targetSize { * layout self and subviews * */ - (void)layoutSelf:(CGSize)targetSize { - CGSize contentSize = [self measureSize:targetSize]; + CGSize contentSize = [self sizeThatFits:targetSize]; if (self.layoutConfig.widthSpec == DoricLayoutAtMost) { self.width = targetSize.width; } else if (self.layoutConfig.widthSpec == DoricLayoutWrapContent) { @@ -108,8 +108,7 @@ - (void)layoutSelf:(CGSize)targetSize { } - (BOOL)requestSuperview { - return self.superview - && self.layoutConfig + return self.layoutConfig && self.layoutConfig.widthSpec != DoricLayoutExact && self.layoutConfig.heightSpec != DoricLayoutExact; } diff --git a/iOS/Pod/Classes/Shader/DoricListNode.m b/iOS/Pod/Classes/Shader/DoricListNode.m index 02751c1b..2ad7e86f 100644 --- a/iOS/Pod/Classes/Shader/DoricListNode.m +++ b/iOS/Pod/Classes/Shader/DoricListNode.m @@ -48,6 +48,11 @@ - (CGSize)sizeThatFits:(CGSize)size { } return size; } + +- (void)layoutSelf:(CGSize)targetSize { + [super layoutSelf:targetSize]; + [self reloadData]; +} @end diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.m b/iOS/Pod/Classes/Shader/DoricScrollerNode.m index 5fb7d0c0..28848f0d 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -34,11 +34,16 @@ - (void)setContentView:(UIView *)contentView { - (CGSize)sizeThatFits:(CGSize)size { if (self.contentView) { - CGSize childSize = [self.contentView sizeThatFits:size]; - return CGSizeMake(MIN(size.width, childSize.width), MIN(size.height, childSize.height)); + return [self.contentView sizeThatFits:size]; } return CGSizeZero; } + +- (void)layoutSelf:(CGSize)targetSize { + [super layoutSelf:targetSize]; + [self.contentView layoutSelf: [self.contentView sizeThatFits:targetSize]]; + [self setContentSize:self.contentView.frame.size]; +} @end @interface DoricScrollerNode () From 91a26eb9a83beeff91f2d351eed2426179fde849 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 16:41:04 +0800 Subject: [PATCH 26/35] feat:step 4 --- iOS/Pod/Classes/Shader/DoricLayouts.m | 19 ++++++------------- iOS/Pod/Classes/Shader/DoricScrollerNode.m | 7 ++++++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index a806496c..883c1625 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -94,17 +94,8 @@ - (CGSize)measureSize:(CGSize)targetSize { * layout self and subviews * */ - (void)layoutSelf:(CGSize)targetSize { - CGSize contentSize = [self sizeThatFits:targetSize]; - if (self.layoutConfig.widthSpec == DoricLayoutAtMost) { - self.width = targetSize.width; - } else if (self.layoutConfig.widthSpec == DoricLayoutWrapContent) { - self.width = contentSize.width; - } - if (self.layoutConfig.heightSpec == DoricLayoutAtMost) { - self.height = targetSize.height; - } else if (self.layoutConfig.heightSpec == DoricLayoutWrapContent) { - self.height = contentSize.height; - } + self.width = targetSize.width; + self.height = targetSize.height; } - (BOOL)requestSuperview { @@ -167,6 +158,10 @@ @interface DoricLayoutContainer () @end @implementation DoricLayoutContainer +- (void)setNeedsLayout { + [super setNeedsLayout]; +} + - (void)layoutSubviews { [super layoutSubviews]; [self doricLayoutSubviews]; @@ -294,8 +289,6 @@ - (CGSize)sizeThatFits:(CGSize)size { - (void)layoutSelf:(CGSize)targetSize { [super layoutSelf:targetSize]; - self.width = targetSize.width; - self.height = targetSize.height; CGFloat yStart = 0; if ((self.gravity & TOP) == TOP) { yStart = 0; diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.m b/iOS/Pod/Classes/Shader/DoricScrollerNode.m index 28848f0d..da6f763c 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -41,9 +41,14 @@ - (CGSize)sizeThatFits:(CGSize)size { - (void)layoutSelf:(CGSize)targetSize { [super layoutSelf:targetSize]; - [self.contentView layoutSelf: [self.contentView sizeThatFits:targetSize]]; + [self.contentView layoutSelf:[self.contentView sizeThatFits:targetSize]]; [self setContentSize:self.contentView.frame.size]; } + +- (CGSize)measureSize:(CGSize)targetSize { + CGSize size = [super measureSize:targetSize]; + return CGSizeMake(MIN(targetSize.width, size.width), MIN(targetSize.height, size.height)); +} @end @interface DoricScrollerNode () From 209a9267fee1046a1bb2c4ae536eed76b65ddd26 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 17:03:20 +0800 Subject: [PATCH 27/35] feat:step5 --- demo/src/LayoutDemo.ts | 8 ++------ iOS/Pod/Classes/Shader/DoricScrollerNode.m | 4 ---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/demo/src/LayoutDemo.ts b/demo/src/LayoutDemo.ts index 4ff2e8a1..442e2844 100644 --- a/demo/src/LayoutDemo.ts +++ b/demo/src/LayoutDemo.ts @@ -1,5 +1,5 @@ -import { Group, Panel, Text, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, slider, slideItem, scroller, IVLayout, IHLayout } from "doric"; +import { Group, Panel, Text, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, slider, slideItem, scroller, IVLayout, IHLayout, layoutConfig } from "doric"; import { O_TRUNC } from "constants"; const colors = [ @@ -453,11 +453,7 @@ class LayoutDemo extends Panel { it.space = 20 }), ).also(it => { - it.layoutConfig = { - widthSpec: LayoutSpec.WRAP_CONTENT, - heightSpec: LayoutSpec.WRAP_CONTENT, - alignment: gravity().centerX(), - } + it.layoutConfig = layoutConfig().atmost() }) .in(rootView) } diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.m b/iOS/Pod/Classes/Shader/DoricScrollerNode.m index da6f763c..091deb79 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -45,10 +45,6 @@ - (void)layoutSelf:(CGSize)targetSize { [self setContentSize:self.contentView.frame.size]; } -- (CGSize)measureSize:(CGSize)targetSize { - CGSize size = [super measureSize:targetSize]; - return CGSizeMake(MIN(targetSize.width, size.width), MIN(targetSize.height, size.height)); -} @end @interface DoricScrollerNode () From e3cb635358eb5f00b7d5d6ab6f1aa0cc9685ab60 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 17:17:03 +0800 Subject: [PATCH 28/35] feat:step6 --- iOS/Pod/Classes/Shader/DoricLayouts.m | 12 +++++++++--- iOS/Pod/Classes/Shader/DoricScrollerNode.m | 1 - iOS/Pod/Classes/Shader/DoricSlideItemNode.m | 3 +++ iOS/Pod/Classes/Shader/DoricSliderNode.m | 10 ++++++++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index 883c1625..72214e07 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -96,6 +96,9 @@ - (CGSize)measureSize:(CGSize)targetSize { - (void)layoutSelf:(CGSize)targetSize { self.width = targetSize.width; self.height = targetSize.height; + for (UIView *view in self.subviews) { + [view layoutSelf:[view measureSize:targetSize]]; + } } - (BOOL)requestSuperview { @@ -202,7 +205,8 @@ - (CGSize)sizeThatFits:(CGSize)size { } - (void)layoutSelf:(CGSize)targetSize { - [super layoutSelf:targetSize]; + self.width = targetSize.width; + self.height = targetSize.height; for (UIView *child in self.subviews) { if (child.isHidden) { continue; @@ -288,7 +292,8 @@ - (CGSize)sizeThatFits:(CGSize)size { } - (void)layoutSelf:(CGSize)targetSize { - [super layoutSelf:targetSize]; + self.width = targetSize.width; + self.height = targetSize.height; CGFloat yStart = 0; if ((self.gravity & TOP) == TOP) { yStart = 0; @@ -378,7 +383,8 @@ - (CGSize)sizeThatFits:(CGSize)size { } - (void)layoutSelf:(CGSize)targetSize { - [super layoutSelf:targetSize]; + self.width = targetSize.width; + self.height = targetSize.height; CGFloat xStart = 0; if (self.contentWeight) { xStart = 0; diff --git a/iOS/Pod/Classes/Shader/DoricScrollerNode.m b/iOS/Pod/Classes/Shader/DoricScrollerNode.m index 091deb79..4d601f15 100644 --- a/iOS/Pod/Classes/Shader/DoricScrollerNode.m +++ b/iOS/Pod/Classes/Shader/DoricScrollerNode.m @@ -41,7 +41,6 @@ - (CGSize)sizeThatFits:(CGSize)size { - (void)layoutSelf:(CGSize)targetSize { [super layoutSelf:targetSize]; - [self.contentView layoutSelf:[self.contentView sizeThatFits:targetSize]]; [self setContentSize:self.contentView.frame.size]; } diff --git a/iOS/Pod/Classes/Shader/DoricSlideItemNode.m b/iOS/Pod/Classes/Shader/DoricSlideItemNode.m index a65cb62e..9e254323 100644 --- a/iOS/Pod/Classes/Shader/DoricSlideItemNode.m +++ b/iOS/Pod/Classes/Shader/DoricSlideItemNode.m @@ -25,6 +25,9 @@ @interface DoricSlideItemView : DoricStackView @end @implementation DoricSlideItemView +- (void)layoutSubviews { + [super layoutSubviews]; +} @end @implementation DoricSlideItemNode diff --git a/iOS/Pod/Classes/Shader/DoricSliderNode.m b/iOS/Pod/Classes/Shader/DoricSliderNode.m index de74db8b..5822745a 100644 --- a/iOS/Pod/Classes/Shader/DoricSliderNode.m +++ b/iOS/Pod/Classes/Shader/DoricSliderNode.m @@ -45,12 +45,18 @@ - (CGSize)sizeThatFits:(CGSize)size { if (self.subviews.count > 0) { CGFloat height = size.height; for (UIView *child in self.subviews) { - height = MAX(child.height, height); + CGSize childSize = [child measureSize:size]; + height = MAX(childSize.height, height); } - return CGSizeMake(height, size.height); + return CGSizeMake(size.width, size.height); } return size; } + +- (void)layoutSelf:(CGSize)targetSize { + [super layoutSelf:targetSize]; + [self reloadData]; +} @end @implementation DoricSliderNode From efd71a69cb2304ce8eee2d38769c615cc1c12af6 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 17:33:47 +0800 Subject: [PATCH 29/35] feat:step7 --- iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m | 12 ++++++++++-- iOS/Pod/Classes/Shader/DoricLayouts.h | 2 ++ iOS/Pod/Classes/Shader/DoricLayouts.m | 15 +++++++++------ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m index f92c0c9f..f5a4bf88 100644 --- a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m @@ -5,7 +5,6 @@ #import "DoricSwipeRefreshLayout.h" #import "UIView+Doric.h" #import "DoricLayouts.h" -#import "Doric.h" @interface DoricSwipeRefreshLayout () @@ -40,9 +39,18 @@ - (CGSize)sizeThatFits:(CGSize)size { return CGSizeZero; } +- (BOOL)requestFromSubview:(UIView *)subview { + if (subview == self.headerView) { + return NO; + } + return [super requestFromSubview:subview]; +} + - (void)layoutSelf:(CGSize)targetSize { [super layoutSelf:targetSize]; - [self.contentView layoutSelf:targetSize]; + self.headerView.bottom = 0; + self.headerView.centerX = self.centerX; + self.contentSize = self.frame.size; } - (void)setContentView:(UIView *)contentView { diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.h b/iOS/Pod/Classes/Shader/DoricLayouts.h index 86824f3c..fcddee0c 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.h +++ b/iOS/Pod/Classes/Shader/DoricLayouts.h @@ -94,4 +94,6 @@ typedef NS_ENUM(NSInteger, DoricGravity) { - (CGSize)measureSize:(CGSize)targetSize; - (void)doricLayoutSubviews; + +- (BOOL)requestFromSubview:(UIView *)subview; @end \ No newline at end of file diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index 72214e07..d1584848 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -101,20 +101,23 @@ - (void)layoutSelf:(CGSize)targetSize { } } -- (BOOL)requestSuperview { - return self.layoutConfig - && self.layoutConfig.widthSpec != DoricLayoutExact - && self.layoutConfig.heightSpec != DoricLayoutExact; -} - (void)doricLayoutSubviews { - if ([self requestSuperview]) { + if ([self.superview requestFromSubview:self]) { [self.superview doricLayoutSubviews]; } else { [self layoutSelf:CGSizeMake(self.width, self.height)]; } } +- (BOOL)requestFromSubview:(UIView *)subview { + if (self.layoutConfig + && self.layoutConfig.widthSpec != DoricLayoutExact + && self.layoutConfig.heightSpec != DoricLayoutExact) { + return YES; + } + return NO; +} @end DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom) { From 0c23be0dea4f52c6c01419c99fcad12517eec770 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 17:41:31 +0800 Subject: [PATCH 30/35] feat:step8 --- iOS/Pod/Classes/Shader/DoricListNode.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iOS/Pod/Classes/Shader/DoricListNode.m b/iOS/Pod/Classes/Shader/DoricListNode.m index 2ad7e86f..aa1d75cc 100644 --- a/iOS/Pod/Classes/Shader/DoricListNode.m +++ b/iOS/Pod/Classes/Shader/DoricListNode.m @@ -121,8 +121,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N DoricListItemNode *node = cell.doricListItemNode; node.viewId = model[@"id"]; [node blend:props]; - [node.view setNeedsLayout]; - CGSize size = [node.view sizeThatFits:CGSizeMake(cell.width, cell.height)]; + CGSize size = [node.view measureSize:CGSizeMake(tableView.width, tableView.height)]; + [node.view layoutSelf:size]; [self callItem:position height:size.height]; return cell; } From f78d2ad487ffcbf58f7a158d3e58a16d01cf22b3 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 17:53:03 +0800 Subject: [PATCH 31/35] feat:step 9 --- iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m index f5a4bf88..95c1f613 100644 --- a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m @@ -80,6 +80,9 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView.contentOffset.y <= 0) { [self.swipePullingDelegate setProgressRotation:-scrollView.contentOffset.y / self.headerView.height]; + self.bounces = YES; + } else { + self.bounces = NO; } } From d8a743f13f4986576f90104d318a3d71df6dbcab Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 18:07:31 +0800 Subject: [PATCH 32/35] feat:step10 --- demo/src/ListDemo.ts | 1 + demo/src/RefreshableDemo.ts | 2 ++ iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m | 11 +++++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/demo/src/ListDemo.ts b/demo/src/ListDemo.ts index 9c037881..81e65d97 100644 --- a/demo/src/ListDemo.ts +++ b/demo/src/ListDemo.ts @@ -109,5 +109,6 @@ class ListPanel extends Panel { } it.bgColor = Color.WHITE }).in(rootView) + refreshView.bgColor = Color.YELLOW } } \ No newline at end of file diff --git a/demo/src/RefreshableDemo.ts b/demo/src/RefreshableDemo.ts index 211108be..0b967c01 100644 --- a/demo/src/RefreshableDemo.ts +++ b/demo/src/RefreshableDemo.ts @@ -102,6 +102,8 @@ class RefreshableDemo extends Panel { } as IVLayout)).apply({ layoutConfig: layoutConfig().atmost(), }) + }).apply({ + bgColor: Color.YELLOW }).in(rootView) } } \ No newline at end of file diff --git a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m index 95c1f613..7f126026 100644 --- a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m @@ -18,6 +18,9 @@ - (instancetype)initWithFrame:(CGRect)frame { self.showsVerticalScrollIndicator = NO; self.alwaysBounceVertical = YES; self.delegate = self; + if (@available(iOS 11, *)) { + self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + } } return self; } @@ -28,6 +31,9 @@ - (instancetype)init { self.showsVerticalScrollIndicator = NO; self.alwaysBounceVertical = YES; self.delegate = self; + if (@available(iOS 11, *)) { + self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + } } return self; } @@ -80,9 +86,10 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView.contentOffset.y <= 0) { [self.swipePullingDelegate setProgressRotation:-scrollView.contentOffset.y / self.headerView.height]; - self.bounces = YES; + //self.bounces = YES; } else { - self.bounces = NO; + //self.bounces = NO; + //scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, 0); } } From ea8ea4a8ff9ef390dd86d4ad5f301f3c61f9dbe4 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 18:32:59 +0800 Subject: [PATCH 33/35] feat:step 11 --- iOS/Pod/Classes/Shader/DoricLayouts.m | 10 ++-------- iOS/Pod/Classes/Shader/DoricSliderNode.m | 3 ++- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index d1584848..902b4478 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -274,9 +274,6 @@ - (CGSize)sizeThatFits:(CGSize)size { CGSize childSize; if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { childSize = [child measureSize:CGSizeMake(size.width, size.height - contentHeight)]; - if (childConfig.weight) { - childSize.height = child.height; - } } else { childSize = child.bounds.size; } @@ -320,7 +317,7 @@ - (void)layoutSelf:(CGSize)targetSize { CGSize size = [child measureSize:CGSizeMake(targetSize.width, targetSize.height - yStart)]; if (childConfig.weight) { - size.height = child.height + remain / self.contentWeight * childConfig.weight; + size.height += remain / self.contentWeight * childConfig.weight; } [child layoutSelf:size]; DoricGravity gravity = childConfig.alignment | self.gravity; @@ -365,9 +362,6 @@ - (CGSize)sizeThatFits:(CGSize)size { CGSize childSize; if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) { childSize = [child measureSize:CGSizeMake(size.width - contentWidth, size.height)]; - if (childConfig.weight) { - childSize.width = child.width; - } } else { childSize = child.bounds.size; } @@ -413,7 +407,7 @@ - (void)layoutSelf:(CGSize)targetSize { CGSize size = [child measureSize:CGSizeMake(targetSize.width - xStart, targetSize.height)]; if (childConfig.weight) { - size.width = child.width + remain / self.contentWeight * childConfig.weight; + size.width += remain / self.contentWeight * childConfig.weight; } [child layoutSelf:size]; diff --git a/iOS/Pod/Classes/Shader/DoricSliderNode.m b/iOS/Pod/Classes/Shader/DoricSliderNode.m index 5822745a..9e495f8c 100644 --- a/iOS/Pod/Classes/Shader/DoricSliderNode.m +++ b/iOS/Pod/Classes/Shader/DoricSliderNode.m @@ -128,7 +128,8 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection DoricSlideItemNode *node = cell.doricSlideItemNode; node.viewId = model[@"id"]; [node blend:props]; - [node.view setNeedsLayout]; + CGSize size = [node.view measureSize:CGSizeMake(collectionView.width, collectionView.height)]; + [node.view layoutSelf:size]; return cell; } From 8b1ed0acc826a37ce9ed83fa9568fca6d46ae2d6 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 19:15:57 +0800 Subject: [PATCH 34/35] feat:Image support animated image --- .../main/java/pub/doric/shader/ImageNode.java | 5 ++- demo/src/ImageDemo.ts | 9 ++++- iOS/Doric.podspec | 5 ++- iOS/Example/Podfile.lock | 37 ++++++++----------- iOS/Pod/Classes/Shader/DoricImageNode.m | 7 ++-- iOS/Pod/Classes/Shader/DoricLayouts.m | 2 - 6 files changed, 31 insertions(+), 34 deletions(-) diff --git a/Android/doric/src/main/java/pub/doric/shader/ImageNode.java b/Android/doric/src/main/java/pub/doric/shader/ImageNode.java index 29a77b41..9157c80d 100644 --- a/Android/doric/src/main/java/pub/doric/shader/ImageNode.java +++ b/Android/doric/src/main/java/pub/doric/shader/ImageNode.java @@ -34,6 +34,7 @@ import com.bumptech.glide.request.target.Target; import pub.doric.DoricContext; import pub.doric.extension.bridge.DoricPlugin; +import pub.doric.utils.DoricUtils; import com.github.pengfeizhou.jscore.JSONBuilder; import com.github.pengfeizhou.jscore.JSValue; @@ -77,8 +78,8 @@ public class ImageNode extends ViewNode { public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { if (!TextUtils.isEmpty(loadCallbackId)) { callJSResponse(loadCallbackId, new JSONBuilder() - .put("width", resource.getIntrinsicWidth()) - .put("height", resource.getIntrinsicHeight()) + .put("width", DoricUtils.px2dp(resource.getIntrinsicWidth())) + .put("height", DoricUtils.px2dp(resource.getIntrinsicHeight())) .toJSONObject()); } return false; diff --git a/demo/src/ImageDemo.ts b/demo/src/ImageDemo.ts index a26c4cee..15ce8d55 100644 --- a/demo/src/ImageDemo.ts +++ b/demo/src/ImageDemo.ts @@ -1,4 +1,4 @@ -import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text, scroller, layoutConfig, image, IView, IVLayout, ScaleType } from "doric"; +import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text, scroller, layoutConfig, image, IView, IVLayout, ScaleType, Image } from "doric"; import { colors, label } from "./utils"; import { img_base64 } from "./image_base64"; const imageUrl = 'https://img.zcool.cn/community/01e75b5da933daa801209e1ffa4649.jpg@1280w_1l_2o_100sh.jpg' @@ -6,6 +6,7 @@ const imageUrl = 'https://img.zcool.cn/community/01e75b5da933daa801209e1ffa4649. @Entry class ImageDemo extends Panel { build(rootView: Group): void { + let imageView: Image scroller(vlayout([ text({ text: "Image Demo", @@ -38,9 +39,13 @@ class ImageDemo extends Panel { } }), label('WebP'), - image({ + imageView = image({ imageUrl: "https://p.upyun.com/demo/webp/webp/jpg-0.webp", loadCallback: (ret) => { + if (ret) { + imageView.width = ret.width + imageView.height = ret.height + } } }), label('ScaleToFill'), diff --git a/iOS/Doric.podspec b/iOS/Doric.podspec index 36590515..8eb2cf33 100644 --- a/iOS/Doric.podspec +++ b/iOS/Doric.podspec @@ -39,8 +39,9 @@ TODO: Add long description of the pod here. s.public_header_files = 'Pod/Classes/**/*.h' # s.frameworks = 'UIKit', 'MapKit' # s.dependency 'AFNetworking', '~> 2.3' - s.dependency 'SDWebImage', '~> 4.4.7' - s.dependency 'SDWebImage/WebP' + # s.dependency 'SDWebImage', '~> 5.0' + s.dependency 'YYWebImage', '~>1.0.5' + s.dependency 'YYImage/WebP' s.dependency 'SocketRocket', '~> 0.5.1' s.dependency 'GCDWebServer', '~> 3.0' s.dependency 'YYCache', '~> 1.0.4' diff --git a/iOS/Example/Podfile.lock b/iOS/Example/Podfile.lock index 1283d0e3..801a54e6 100644 --- a/iOS/Example/Podfile.lock +++ b/iOS/Example/Podfile.lock @@ -1,30 +1,23 @@ PODS: - Doric (0.1.0): - GCDWebServer (~> 3.0) - - SDWebImage (~> 4.4.7) - - SDWebImage/WebP - SocketRocket (~> 0.5.1) - YYCache (~> 1.0.4) + - YYImage/WebP + - YYWebImage - GCDWebServer (3.5.3): - GCDWebServer/Core (= 3.5.3) - GCDWebServer/Core (3.5.3) - - libwebp (1.0.3): - - libwebp/demux (= 1.0.3) - - libwebp/mux (= 1.0.3) - - libwebp/webp (= 1.0.3) - - libwebp/demux (1.0.3): - - libwebp/webp - - libwebp/mux (1.0.3): - - libwebp/demux - - libwebp/webp (1.0.3) - - SDWebImage (4.4.7): - - SDWebImage/Core (= 4.4.7) - - SDWebImage/Core (4.4.7) - - SDWebImage/WebP (4.4.7): - - libwebp (< 2.0, >= 0.5) - - SDWebImage/Core - SocketRocket (0.5.1) - YYCache (1.0.4) + - YYImage (1.0.4): + - YYImage/Core (= 1.0.4) + - YYImage/Core (1.0.4) + - YYImage/WebP (1.0.4): + - YYImage/Core + - YYWebImage (1.0.5): + - YYCache + - YYImage DEPENDENCIES: - Doric (from `../`) @@ -32,22 +25,22 @@ DEPENDENCIES: SPEC REPOS: https://github.com/cocoapods/specs.git: - GCDWebServer - - libwebp - - SDWebImage - SocketRocket - YYCache + - YYImage + - YYWebImage EXTERNAL SOURCES: Doric: :path: "../" SPEC CHECKSUMS: - Doric: c71287d68afeeb79bfd3c680ed2dd3b90d515c12 + Doric: e73b17b0e46198994f5c3d8af49f26fd9f49df09 GCDWebServer: c0ab22c73e1b84f358d1e2f74bf6afd1c60829f2 - libwebp: 057912d6d0abfb6357d8bb05c0ea470301f5d61e - SDWebImage: c10d14a8883ebd89664f02a422006f66a85c0c5d SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531 YYCache: 8105b6638f5e849296c71f331ff83891a4942952 + YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54 + YYWebImage: 5f7f36aee2ae293f016d418c7d6ba05c4863e928 PODFILE CHECKSUM: 012563d71439e7e33e976dca3b59664ed56cee39 diff --git a/iOS/Pod/Classes/Shader/DoricImageNode.m b/iOS/Pod/Classes/Shader/DoricImageNode.m index 6670a4fd..95cfd878 100644 --- a/iOS/Pod/Classes/Shader/DoricImageNode.m +++ b/iOS/Pod/Classes/Shader/DoricImageNode.m @@ -22,7 +22,7 @@ #import "DoricImageNode.h" #import "Doric.h" -#import +#import "YYWebImage.h" @interface DoricImageNode () @property(nonatomic, copy) NSString *loadCallbackId; @@ -31,7 +31,7 @@ @interface DoricImageNode () @implementation DoricImageNode - (UIImageView *)build { - return [[UIImageView new] also:^(UIImageView *it) { + return [[YYAnimatedImageView new] also:^(UIImageView *it) { it.clipsToBounds = YES; }]; } @@ -39,7 +39,7 @@ - (UIImageView *)build { - (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id)prop { if ([@"imageUrl" isEqualToString:name]) { __weak typeof(self) _self = self; - [view sd_setImageWithURL:[NSURL URLWithString:prop] completed:^(UIImage *_Nullable image, NSError *_Nullable error, SDImageCacheType cacheType, NSURL *_Nullable imageURL) { + [view yy_setImageWithURL:[NSURL URLWithString:prop] placeholder:nil options:0 completion:^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) { __strong typeof(_self) self = _self; if (error) { if (self.loadCallbackId.length > 0) { @@ -53,7 +53,6 @@ - (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id } [self requestLayout]; } - }]; } else if ([@"scaleType" isEqualToString:name]) { switch ([prop integerValue]) { diff --git a/iOS/Pod/Classes/Shader/DoricLayouts.m b/iOS/Pod/Classes/Shader/DoricLayouts.m index 902b4478..c1e0adfb 100644 --- a/iOS/Pod/Classes/Shader/DoricLayouts.m +++ b/iOS/Pod/Classes/Shader/DoricLayouts.m @@ -176,8 +176,6 @@ - (void)layoutSubviews { @interface DoricStackView () -@property(nonatomic, assign) CGFloat contentWidth; -@property(nonatomic, assign) CGFloat contentHeight; @end @implementation DoricStackView From 459aab61e32714e525b604a3d5ebb10b5575a7be Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Nov 2019 19:57:43 +0800 Subject: [PATCH 35/35] feat:optimize refreshable --- .../Classes/Refresh/DoricRefreshableNode.m | 2 +- .../Classes/Refresh/DoricSwipeRefreshLayout.m | 26 +++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m index 137dc5e2..bb17e312 100644 --- a/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m +++ b/iOS/Pod/Classes/Refresh/DoricRefreshableNode.m @@ -143,7 +143,7 @@ - (void)setProgressRotation:(CGFloat)rotation { - (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.m b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m index 7f126026..fc1c94fb 100644 --- a/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m +++ b/iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m @@ -76,23 +76,24 @@ - (void)setHeaderView:(UIView *)headerView { self.refreshable = YES; } - - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (-scrollView.contentOffset.y >= self.headerView.height) { - self.refreshing = YES; + dispatch_async(dispatch_get_main_queue(), ^{ + self.refreshing = YES; + }); } } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView.contentOffset.y <= 0) { [self.swipePullingDelegate setProgressRotation:-scrollView.contentOffset.y / self.headerView.height]; - //self.bounces = YES; - } else { - //self.bounces = NO; - //scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, 0); } } +- (void)setContentOffset:(CGPoint)contentOffset { + [super setContentOffset:contentOffset]; +} + - (void)setRefreshing:(BOOL)refreshing { if (_refreshing == refreshing) { return; @@ -101,21 +102,26 @@ - (void)setRefreshing:(BOOL)refreshing { if (self.onRefreshBlock) { self.onRefreshBlock(); } - [UIView animateWithDuration:0.3f + [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 { - [UIView animateWithDuration:0.3f + 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; } ]; } @@ -124,6 +130,10 @@ - (void)setRefreshing:(BOOL)refreshing { - (void)setRefreshable:(BOOL)refreshable { self.scrollEnabled = refreshable; + if (refreshable) { + self.contentOffset = (CGPoint) {0, 0}; + self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); + } } - (BOOL)refreshable {