feat(android): add nestedScrollPriority for ListView and ScrollView

* feat(android): squash branch scroll_conflict (#6)

* fix(android): nested scroll feature

  - edit priority api
  - scrollview prevent nested scroll when enabled paging
  - fix viewpager vertical issue
  - viewpager nested scroll
  - translate comments

* fix(android): Eltonqin/netscroll bugfix (#3)

* fix(android):HorizonScrollView may throw exception when handle onInterceptTouchEvent

* fix(android):post task still run after remove

* fix(android):post task still run after remove,modify format

Co-authored-by: eltonqin <eltonqin@tencent.com>

* fix(android): nested scroll feature

  - viewpager nested scroll issue

* feat(docs): update docs

Co-authored-by: HOHOHOTangoDown <iystina7@gmail.com>
Co-authored-by: eltonqin <eltonqin@tencent.com>

* fix(android): nested scroll conflicts with pull refresh

* feat(docs, demo): update docs and demos

Co-authored-by: HOHOHOTangoDown <iystina7@gmail.com>
Co-authored-by: eltonqin <eltonqin@tencent.com>
This commit is contained in:
iPel
2023-02-06 16:56:53 +08:00
committed by zoomchan-cxj
co-authored by eltonqin HOHOHOTangoDown
parent 0819440e59
commit 4e34fc1471
19 changed files with 931 additions and 76 deletions
@@ -36,6 +36,8 @@ import com.tencent.mtt.hippy.modules.Promise;
import com.tencent.mtt.hippy.utils.LogUtils;
import com.tencent.mtt.hippy.utils.PixelUtil;
import com.tencent.mtt.hippy.views.common.CommonBorder;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollHelper;
import com.tencent.mtt.hippy.views.hippylist.HippyRecyclerViewWrapper;
import com.tencent.mtt.hippy.views.list.HippyListView;
import com.tencent.mtt.hippy.views.scroll.HippyScrollView;
@@ -640,6 +642,52 @@ public abstract class HippyViewController<T extends View & HippyViewBase> implem
view.setLayerType(useHWTexture ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
}
@HippyControllerProps(name = HippyNestedScrollComponent.PROP_PRIORITY, defaultType =
HippyControllerProps.STRING, defaultString = HippyNestedScrollComponent.PRIORITY_SELF)
public void setNestedScrollPriority(T view, String priorityName) {
if (view instanceof HippyNestedScrollComponent) {
HippyNestedScrollComponent sc = (HippyNestedScrollComponent) view;
HippyNestedScrollComponent.Priority priority = HippyNestedScrollHelper.priorityOf(priorityName);
sc.setNestedScrollPriority(HippyNestedScrollComponent.DIRECTION_ALL, priority);
}
}
@HippyControllerProps(name = HippyNestedScrollComponent.PROP_LEFT_PRIORITY, defaultType =
HippyControllerProps.STRING, defaultString = HippyNestedScrollComponent.PRIORITY_SELF)
public void setNestedScrollLeftPriority(T view, String priorityName) {
if (view instanceof HippyNestedScrollComponent) {
HippyNestedScrollComponent.Priority priority = HippyNestedScrollHelper.priorityOf(priorityName);
((HippyNestedScrollComponent) view).setNestedScrollPriority(HippyNestedScrollComponent.DIRECTION_LEFT, priority);
}
}
@HippyControllerProps(name = HippyNestedScrollComponent.PROP_TOP_PRIORITY, defaultType =
HippyControllerProps.STRING, defaultString = HippyNestedScrollComponent.PRIORITY_SELF)
public void setNestedScrollTopPriority(T view, String priorityName) {
if (view instanceof HippyNestedScrollComponent) {
HippyNestedScrollComponent.Priority priority = HippyNestedScrollHelper.priorityOf(priorityName);
((HippyNestedScrollComponent) view).setNestedScrollPriority(HippyNestedScrollComponent.DIRECTION_TOP, priority);
}
}
@HippyControllerProps(name = HippyNestedScrollComponent.PROP_RIGHT_PRIORITY, defaultType =
HippyControllerProps.STRING, defaultString = HippyNestedScrollComponent.PRIORITY_SELF)
public void setNestedScrollRightPriority(T view, String priorityName) {
if (view instanceof HippyNestedScrollComponent) {
HippyNestedScrollComponent.Priority priority = HippyNestedScrollHelper.priorityOf(priorityName);
((HippyNestedScrollComponent) view).setNestedScrollPriority(HippyNestedScrollComponent.DIRECTION_RIGHT, priority);
}
}
@HippyControllerProps(name = HippyNestedScrollComponent.PROP_BOTTOM_PRIORITY, defaultType =
HippyControllerProps.STRING, defaultString = HippyNestedScrollComponent.PRIORITY_SELF)
public void setNestedScrollBottomPriority(T view, String priorityName) {
if (view instanceof HippyNestedScrollComponent) {
HippyNestedScrollComponent.Priority priority = HippyNestedScrollHelper.priorityOf(priorityName);
((HippyNestedScrollComponent) view).setNestedScrollPriority(HippyNestedScrollComponent.DIRECTION_BOTTOM, priority);
}
}
@SuppressWarnings("EmptyMethod")
@HippyControllerProps(name = NodeProps.CUSTOM_PROP)
public void setCustomProp(T view, String methodName, Object props) {
@@ -0,0 +1,69 @@
/* Tencent is pleased to support the open source community by making Hippy available.
* Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* 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 com.tencent.mtt.hippy.views.common;
import androidx.core.view.NestedScrollingChild;
import androidx.core.view.NestedScrollingChild2;
import androidx.core.view.NestedScrollingParent;
import androidx.core.view.NestedScrollingParent2;
public interface HippyNestedScrollComponent {
String PROP_PRIORITY = "nestedScrollPriority";
String PROP_LEFT_PRIORITY = "nestedScrollLeftPriority";
String PROP_TOP_PRIORITY = "nestedScrollTopPriority";
String PROP_RIGHT_PRIORITY = "nestedScrollRightPriority";
String PROP_BOTTOM_PRIORITY = "nestedScrollBottomPriority";
String PRIORITY_PARENT = "parent";
String PRIORITY_SELF = "self";
String PRIORITY_NONE = "none";
int DIRECTION_INVALID = -1;
int DIRECTION_ALL = 0;
int DIRECTION_LEFT = 1;
int DIRECTION_TOP = 2;
int DIRECTION_RIGHT = 3;
int DIRECTION_BOTTOM = 4;
void setNestedScrollPriority(int direction, Priority priority);
Priority getNestedScrollPriority(int direction);
enum Priority {
NOT_SET,
PARENT,
SELF,
NONE,
}
/**
* Nested scroll interface declaration
*/
interface HippyNestedScrollTarget extends HippyNestedScrollComponent, NestedScrollingParent,
NestedScrollingChild {
}
/**
* Added non-touch scrolling type than {@link HippyNestedScrollTarget}
*/
interface HippyNestedScrollTarget2 extends HippyNestedScrollTarget, NestedScrollingParent2,
NestedScrollingChild2 {
}
}
@@ -0,0 +1,73 @@
/* Tencent is pleased to support the open source community by making Hippy available.
* Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* 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 com.tencent.mtt.hippy.views.common;
import static com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.DIRECTION_BOTTOM;
import static com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.DIRECTION_LEFT;
import static com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.DIRECTION_RIGHT;
import static com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.DIRECTION_TOP;
import static com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.PRIORITY_NONE;
import static com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.PRIORITY_PARENT;
import static com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.PRIORITY_SELF;
import static com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.Priority;
import android.view.View;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.HippyNestedScrollTarget;
public class HippyNestedScrollHelper {
public static Priority priorityOf(String name) {
switch (name) {
case PRIORITY_SELF:
return Priority.SELF;
case PRIORITY_PARENT:
return Priority.PARENT;
case PRIORITY_NONE:
return Priority.NONE;
default:
throw new RuntimeException("Invalid priority: " + name);
}
}
public static Priority priorityOfX(View target, int dx) {
// not scrolling, priority is NONE
if (dx == 0) {
return Priority.NONE;
}
// non-HippyNestedScrollTarget View, priority is SELF
if (!(target instanceof HippyNestedScrollTarget)) {
return Priority.SELF;
}
// get priority from target by direction
return ((HippyNestedScrollTarget) target).getNestedScrollPriority(
dx > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT);
}
public static Priority priorityOfY(View target, int dy) {
// not scrolling, priority is NONE
if (dy == 0) {
return Priority.NONE;
}
// non-HippyNestedScrollTarget View, priority is SELF
if (!(target instanceof HippyNestedScrollTarget)) {
return Priority.SELF;
}
// get priority from target by direction
return ((HippyNestedScrollTarget) target).getNestedScrollPriority(
dy > 0 ? DIRECTION_TOP : DIRECTION_BOTTOM);
}
}
@@ -25,12 +25,9 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.NestedScrollingChild2;
import androidx.core.view.NestedScrollingParent2;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.HippyRecyclerViewBase;
import androidx.recyclerview.widget.IHippyViewAboundListener;
@@ -38,6 +35,8 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import com.tencent.mtt.hippy.HippyEngineContext;
import com.tencent.mtt.hippy.utils.LogUtils;
import com.tencent.mtt.hippy.utils.PixelUtil;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.HippyNestedScrollTarget2;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollHelper;
import com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.IHeaderAttachListener;
import com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.IHeaderHost;
import com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.StickyHeaderHelper;
@@ -46,8 +45,7 @@ import com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.StickyHe
* Created on 2020/12/22. Description
*/
public class HippyRecyclerView<ADP extends HippyRecyclerListAdapter> extends HippyRecyclerViewBase
implements IHeaderAttachListener, IHippyViewAboundListener,
NestedScrollingChild2, NestedScrollingParent2 {
implements IHeaderAttachListener, IHippyViewAboundListener, HippyNestedScrollTarget2 {
private static int DEFAULT_ITEM_VIEW_CACHE_SIZE = 8;
protected HippyEngineContext hippyEngineContext;
@@ -65,6 +63,8 @@ public class HippyRecyclerView<ADP extends HippyRecyclerListAdapter> extends Hip
private boolean isTvPlatform = false;
private HippyRecycleViewFocusHelper mFocusHelper = null;
private final int[] mScrollConsumedPair = new int[2];
private final Priority[] mNestedScrollPriority = {Priority.SELF, Priority.NOT_SET,
Priority.NOT_SET, Priority.NOT_SET, Priority.NOT_SET};
private int mNestedScrollAxesTouch;
private int mNestedScrollAxesNonTouch;
@@ -676,6 +676,20 @@ public class HippyRecyclerView<ADP extends HippyRecyclerListAdapter> extends Hip
&& listAdapter.footerRefreshHelper.getVisibleSize() > 0;
}
@Override
public void setNestedScrollPriority(int direction, Priority priority) {
mNestedScrollPriority[direction] = priority;
}
@Override
public Priority getNestedScrollPriority(int direction) {
Priority result = mNestedScrollPriority[direction];
if (result == Priority.NOT_SET) {
result = mNestedScrollPriority[DIRECTION_ALL];
}
return result;
}
private int computeHorizontallyScrollDistance(int dx) {
if (dx < 0) {
return Math.max(dx, -computeHorizontalScrollOffset());
@@ -764,33 +778,36 @@ public class HippyRecyclerView<ADP extends HippyRecyclerListAdapter> extends Hip
@Override
public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
int dxUnconsumed,
int dyUnconsumed) {
int dxUnconsumed, int dyUnconsumed) {
onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
ViewCompat.TYPE_TOUCH);
}
@Override
public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
int dxUnconsumed,
int dyUnconsumed, int type) {
int dxUnconsumed, int dyUnconsumed, int type) {
// Step 1: process pull refresh
if (type == ViewCompat.TYPE_TOUCH) {
mScrollConsumedPair[0] = 0;
mScrollConsumedPair[1] = 0;
if (handlePullRefresh(dxUnconsumed, dyUnconsumed, mScrollConsumedPair)) {
dxConsumed += mScrollConsumedPair[0];
dyConsumed += mScrollConsumedPair[1];
dxUnconsumed -= mScrollConsumedPair[0];
dyUnconsumed -= mScrollConsumedPair[1];
if (HippyNestedScrollHelper.priorityOfX(target, dxUnconsumed) == Priority.SELF
|| HippyNestedScrollHelper.priorityOfY(target, dyUnconsumed) == Priority.SELF) {
mScrollConsumedPair[0] = 0;
mScrollConsumedPair[1] = 0;
if (handlePullRefresh(dxUnconsumed, dyUnconsumed, mScrollConsumedPair)) {
dxConsumed += mScrollConsumedPair[0];
dyConsumed += mScrollConsumedPair[1];
dxUnconsumed -= mScrollConsumedPair[0];
dyUnconsumed -= mScrollConsumedPair[1];
}
}
} else if (isPullRefreshShowing()) {
// don't respond non-touch scroll, prevent header/footer scroll to wrong position
return;
}
// Step 2: process the current View
int myDx = dxUnconsumed != 0 ? computeHorizontallyScrollDistance(dxUnconsumed) : 0;
int myDy = dyUnconsumed != 0 ? computeVerticallyScrollDistance(dyUnconsumed) : 0;
int myDx = HippyNestedScrollHelper.priorityOfX(target, dxUnconsumed) == Priority.SELF
? computeHorizontallyScrollDistance(dxUnconsumed) : 0;
int myDy = HippyNestedScrollHelper.priorityOfY(target, dyUnconsumed) == Priority.SELF
? computeVerticallyScrollDistance(dyUnconsumed) : 0;
if (myDx != 0 || myDy != 0) {
scrollBy(myDx, myDy);
dxConsumed += myDx;
@@ -799,8 +816,10 @@ public class HippyRecyclerView<ADP extends HippyRecyclerListAdapter> extends Hip
dyUnconsumed -= myDy;
}
// Step 3: dispatch to the parent for processing
int parentDx = dxUnconsumed;
int parentDy = dyUnconsumed;
int parentDx = HippyNestedScrollHelper.priorityOfX(this, dxUnconsumed) == Priority.NONE ? 0
: dxUnconsumed;
int parentDy = HippyNestedScrollHelper.priorityOfY(this, dyUnconsumed) == Priority.NONE ? 0
: dyUnconsumed;
if (parentDx != 0 || parentDy != 0) {
dispatchNestedScroll(dxConsumed, dyConsumed, parentDx, parentDy, null, type);
}
@@ -814,19 +833,47 @@ public class HippyRecyclerView<ADP extends HippyRecyclerListAdapter> extends Hip
@Override
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed,
int type) {
// Dispatch to the parent for processing first
int parentDx = dx;
int parentDy = dy;
// Step 1: Dispatch to the parent for processing
int parentDx = HippyNestedScrollHelper.priorityOfX(this, dx) == Priority.NONE ? 0 : dx;
int parentDy = HippyNestedScrollHelper.priorityOfY(this, dy) == Priority.NONE ? 0 : dy;
if (parentDx != 0 || parentDy != 0) {
// Temporarily store `consumed` to reuse the Array
int consumedX = consumed[0];
int consumedY = consumed[1];
consumed[0] = 0;
consumed[1] = 0;
mScrollConsumedPair[0] = 0;
mScrollConsumedPair[1] = 0;
// must use super to prevent duplicate handlePullRefresh
super.dispatchNestedPreScroll(parentDx, parentDy, consumed, null, type);
consumed[0] += consumedX;
consumed[1] += consumedY;
super.dispatchNestedPreScroll(parentDx, parentDy, mScrollConsumedPair, null, type);
consumed[0] += mScrollConsumedPair[0];
consumed[1] += mScrollConsumedPair[1];
dx -= mScrollConsumedPair[0];
dy -= mScrollConsumedPair[1];
}
// Step 2: process pull refresh
if (HippyNestedScrollHelper.priorityOfX(target, dx) == Priority.PARENT
|| HippyNestedScrollHelper.priorityOfY(target, dy) == Priority.PARENT) {
if (type == ViewCompat.TYPE_TOUCH) {
mScrollConsumedPair[0] = 0;
mScrollConsumedPair[1] = 0;
if (handlePullRefresh(dx, dy, mScrollConsumedPair)) {
consumed[0] += mScrollConsumedPair[0];
consumed[1] += mScrollConsumedPair[1];
dx -= mScrollConsumedPair[0];
dy -= mScrollConsumedPair[1];
}
} else if (isPullRefreshShowing()) {
// don't respond non-touch scroll, prevent header/footer scroll to wrong position
consumed[0] += dx;
consumed[1] += dy;
return;
}
}
// Step 3: process the current View
int myDx = HippyNestedScrollHelper.priorityOfX(target, dx) == Priority.PARENT
? computeHorizontallyScrollDistance(dx) : 0;
int myDy = HippyNestedScrollHelper.priorityOfY(target, dy) == Priority.PARENT
? computeVerticallyScrollDistance(dy) : 0;
if (myDx != 0 || myDy != 0) {
consumed[0] += myDx;
consumed[1] += myDy;
scrollBy(myDx, myDy);
}
}
@@ -18,17 +18,18 @@ package com.tencent.mtt.hippy.views.hippylist;
import android.content.Context;
import android.os.Build.VERSION_CODES;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.recyclerview.widget.HippyRecyclerExtension;
import androidx.recyclerview.widget.HippyRecyclerPool;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.FrameLayout;
import com.tencent.mtt.hippy.HippyEngineContext;
import com.tencent.mtt.hippy.HippyInstanceContext;
import com.tencent.mtt.hippy.uimanager.HippyViewBase;
import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent;
import com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.IHeaderHost;
/**
@@ -39,7 +40,7 @@ import com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.IHeaderH
* 这样不会影响RecyclerView的Layout的排版,否则就需要重写LayoutManager,重新layoutManager也是后面要考虑的。
*/
public class HippyRecyclerViewWrapper<HRCV extends HippyRecyclerView> extends FrameLayout implements HippyViewBase,
IHeaderHost {
IHeaderHost, HippyNestedScrollComponent {
protected final HippyEngineContext hpContext;
protected HRCV recyclerView;
@@ -144,4 +145,14 @@ public class HippyRecyclerViewWrapper<HRCV extends HippyRecyclerView> extends Fr
public void onBatchComplete() {
recyclerView.onBatchComplete();
}
@Override
public void setNestedScrollPriority(int direction, Priority priority) {
recyclerView.setNestedScrollPriority(direction, priority);
}
@Override
public Priority getNestedScrollPriority(int direction) {
return recyclerView.getNestedScrollPriority(direction);
}
}
@@ -33,12 +33,14 @@ import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher;
import com.tencent.mtt.hippy.utils.I18nUtil;
import com.tencent.mtt.hippy.utils.LogUtils;
import com.tencent.mtt.hippy.utils.PixelUtil;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.HippyNestedScrollTarget;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollHelper;
import com.tencent.mtt.supportui.views.ScrollChecker;
import java.util.HashMap;
@SuppressWarnings("deprecation")
public class HippyHorizontalScrollView extends HorizontalScrollView implements HippyViewBase,
HippyScrollView, ScrollChecker.IScrollCheck, NestedScrollingParent2 {
HippyScrollView, ScrollChecker.IScrollCheck, HippyNestedScrollTarget, NestedScrollingParent2 {
private NativeGestureDispatcher mGestureDispatcher;
@@ -77,6 +79,7 @@ public class HippyHorizontalScrollView extends HorizontalScrollView implements H
private HippyHorizontalScrollViewFocusHelper mFocusHelper = null;
private HashMap<Integer, Integer> scrollOffsetForReuse = new HashMap<>();
private final Priority[] mNestedScrollPriority = { Priority.SELF, Priority.NOT_SET, Priority.NOT_SET, Priority.NOT_SET, Priority.NOT_SET };
private final int[] mScrollConsumedPair = new int[2];
private final int[] mScrollOffsetPair = new int[2];
private final NestedScrollingChildHelper mChildHelper = new NestedScrollingChildHelper(this);
@@ -271,7 +274,8 @@ public class HippyHorizontalScrollView extends HorizontalScrollView implements H
public int getOverScrollMode() {
// If nested scrolling occurs, remove the overScrollMode to avoid triggering the rebound effect
// by mistake
if (!hasNestedScrollingParent()) {
if (!hasNestedScrollingParent() || getNestedScrollPriority(DIRECTION_LEFT) == Priority.NONE
&& getNestedScrollPriority(DIRECTION_RIGHT) == Priority.NONE) {
return super.getOverScrollMode();
}
return OVER_SCROLL_NEVER;
@@ -280,7 +284,8 @@ public class HippyHorizontalScrollView extends HorizontalScrollView implements H
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
if (!isTouchEvent || !hasNestedScrollingParent() || deltaX == 0) {
if (!isTouchEvent || !hasNestedScrollingParent()
|| HippyNestedScrollHelper.priorityOfX(this, deltaX) == Priority.NONE) {
// without nested scrolling
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY,
maxOverScrollX, maxOverScrollY, isTouchEvent);
@@ -517,6 +522,20 @@ public class HippyHorizontalScrollView extends HorizontalScrollView implements H
super.requestChildFocus(child, focused);
}
@Override
public void setNestedScrollPriority(int direction, Priority priority) {
mNestedScrollPriority[direction] = priority;
}
@Override
public Priority getNestedScrollPriority(int direction) {
Priority result = mNestedScrollPriority[direction];
if (result == Priority.NOT_SET) {
result = mNestedScrollPriority[DIRECTION_ALL];
}
return result;
}
@Override
public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes) {
return onStartNestedScroll(child, target, axes, ViewCompat.TYPE_TOUCH);
@@ -558,7 +577,7 @@ public class HippyHorizontalScrollView extends HorizontalScrollView implements H
return;
}
// Process the current View first
if (dxUnconsumed != 0) {
if (HippyNestedScrollHelper.priorityOfX(target, dxUnconsumed) == Priority.SELF) {
final int oldScrollX = getScrollX();
scrollBy(dxUnconsumed, 0);
final int myConsumed = getScrollX() - oldScrollX;
@@ -566,8 +585,8 @@ public class HippyHorizontalScrollView extends HorizontalScrollView implements H
dxUnconsumed -= myConsumed;
}
// Then dispatch to the parent for processing
int parentDx = dxUnconsumed;
int parentDy = dyUnconsumed;
int parentDx = HippyNestedScrollHelper.priorityOfX(this, dxUnconsumed) == Priority.NONE ? 0 : dxUnconsumed;
int parentDy = HippyNestedScrollHelper.priorityOfY(this, dyUnconsumed) == Priority.NONE ? 0 : dyUnconsumed;
if (parentDx != 0 || parentDy != 0) {
if (type == ViewCompat.TYPE_TOUCH) {
dispatchNestedScroll(dxConsumed, dyConsumed, parentDx, parentDy, null);
@@ -585,11 +604,14 @@ public class HippyHorizontalScrollView extends HorizontalScrollView implements H
@Override
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
if (mPagingEnabled && type == ViewCompat.TYPE_NON_TOUCH) {
if (HippyNestedScrollHelper.priorityOfY(target, dy) == Priority.PARENT) {
consumed[0] += dx;
}
return;
}
// Dispatch to the parent for processing first
int parentDx = dx;
int parentDy = dy;
int parentDx = HippyNestedScrollHelper.priorityOfX(this, dx) == Priority.NONE ? 0 : dx;
int parentDy = HippyNestedScrollHelper.priorityOfY(this, dy) == Priority.NONE ? 0 : dy;
if (parentDx != 0 || parentDy != 0) {
// Temporarily store `consumed` to reuse the Array
int consumedX = consumed[0];
@@ -601,9 +623,17 @@ public class HippyHorizontalScrollView extends HorizontalScrollView implements H
} else {
mChildHelper.dispatchNestedPreScroll(parentDx, parentDy, consumed, null, type);
}
dx -= consumed[0];
consumed[0] += consumedX;
consumed[1] += consumedY;
}
// Then process the current View
if (HippyNestedScrollHelper.priorityOfX(target, dx) == Priority.PARENT) {
final int oldScrollX = getScrollX();
scrollBy(dx, 0);
final int myConsumed = getScrollX() - oldScrollX;
consumed[0] += myConsumed;
}
}
@Override
@@ -22,8 +22,6 @@ import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.view.NestedScrollingChild2;
import androidx.core.view.NestedScrollingParent2;
import androidx.core.view.ViewCompat;
import androidx.core.widget.NestedScrollView;
import com.tencent.mtt.hippy.HippyEngineContext;
@@ -32,11 +30,13 @@ import com.tencent.mtt.hippy.common.HippyMap;
import com.tencent.mtt.hippy.uimanager.HippyViewBase;
import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher;
import com.tencent.mtt.hippy.utils.PixelUtil;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.HippyNestedScrollTarget2;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollHelper;
import java.util.ArrayList;
@SuppressWarnings("deprecation")
public class HippyVerticalScrollView extends NestedScrollView implements HippyViewBase,
HippyScrollView, NestedScrollingParent2, NestedScrollingChild2 {
HippyScrollView, HippyNestedScrollTarget2 {
private NativeGestureDispatcher mGestureDispatcher;
@@ -73,6 +73,8 @@ public class HippyVerticalScrollView extends NestedScrollView implements HippyVi
private boolean hasCompleteFirstBatch = false;
private HippyVerticalScrollViewFocusHelper mFocusHelper = null;
private final boolean isTvPlatform;
private final Priority[] mNestedScrollPriority = {Priority.SELF, Priority.NOT_SET,
Priority.NOT_SET, Priority.NOT_SET, Priority.NOT_SET};
private final Runnable mDoPageScrollRunnable = this::doPageScroll;
private final Runnable mComputeScrollRunnable = HippyVerticalScrollView.super::computeScroll;
@@ -403,6 +405,20 @@ public class HippyVerticalScrollView extends NestedScrollView implements HippyVi
}
}
@Override
public void setNestedScrollPriority(int direction, Priority priority) {
mNestedScrollPriority[direction] = priority;
}
@Override
public Priority getNestedScrollPriority(int direction) {
Priority result = mNestedScrollPriority[direction];
if (result == Priority.NOT_SET) {
result = mNestedScrollPriority[DIRECTION_ALL];
}
return result;
}
@Override
public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes, int type) {
if (!mScrollEnabled) {
@@ -438,7 +454,7 @@ public class HippyVerticalScrollView extends NestedScrollView implements HippyVi
}
int myConsumed = 0;
// Process the current View first
if (dyUnconsumed != 0) {
if (HippyNestedScrollHelper.priorityOfY(target, dyUnconsumed) == Priority.SELF) {
final int oldScrollY = getScrollY();
scrollBy(0, dyUnconsumed);
myConsumed = getScrollY() - oldScrollY;
@@ -446,8 +462,8 @@ public class HippyVerticalScrollView extends NestedScrollView implements HippyVi
dyUnconsumed -= myConsumed;
}
// Then dispatch to the parent for processing
int parentDx = dxUnconsumed;
int parentDy = dyUnconsumed;
int parentDx = HippyNestedScrollHelper.priorityOfX(this, dxUnconsumed) == Priority.NONE ? 0 : dxUnconsumed;
int parentDy = HippyNestedScrollHelper.priorityOfY(this, dyUnconsumed) == Priority.NONE ? 0 : dyUnconsumed;
if (parentDx != 0 || parentDy != 0) {
if (consumed == null) {
dispatchNestedScroll(dxConsumed, dyConsumed, parentDx, parentDy, null, type);
@@ -466,11 +482,14 @@ public class HippyVerticalScrollView extends NestedScrollView implements HippyVi
@Override
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
if (mPagingEnabled && type == ViewCompat.TYPE_NON_TOUCH) {
if (HippyNestedScrollHelper.priorityOfY(target, dy) == Priority.PARENT) {
consumed[1] += dy;
}
return;
}
// Dispatch to the parent for processing first
int parentDx = dx;
int parentDy = dy;
int parentDx = HippyNestedScrollHelper.priorityOfX(this, dx) == Priority.NONE ? 0 : dx;
int parentDy = HippyNestedScrollHelper.priorityOfY(this, dy) == Priority.NONE ? 0 : dy;
if (parentDx != 0 || parentDy != 0) {
// Temporarily store `consumed` to reuse the Array
int consumedX = consumed[0];
@@ -478,9 +497,17 @@ public class HippyVerticalScrollView extends NestedScrollView implements HippyVi
consumed[0] = 0;
consumed[1] = 0;
dispatchNestedPreScroll(parentDx, parentDy, consumed, null, type);
dy -= consumed[1];
consumed[0] += consumedX;
consumed[1] += consumedY;
}
// Then process the current View
if (HippyNestedScrollHelper.priorityOfY(target, dy) == Priority.PARENT) {
final int oldScrollY = getScrollY();
scrollBy(0, dy);
final int myConsumed = getScrollY() - oldScrollY;
consumed[1] += myConsumed;
}
}
@Override
@@ -29,6 +29,8 @@ import com.tencent.mtt.hippy.uimanager.HippyViewBase;
import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher;
import com.tencent.mtt.hippy.utils.I18nUtil;
import com.tencent.mtt.hippy.utils.LogUtils;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollComponent.Priority;
import com.tencent.mtt.hippy.views.common.HippyNestedScrollHelper;
import com.tencent.mtt.supportui.views.viewpager.ViewPager;
@SuppressWarnings({"unused"})
@@ -321,6 +323,17 @@ public class HippyViewPager extends ViewPager implements HippyViewBase {
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed) {
// viewpager does not support nested scrolling, only when it cannot scroll, will the event from
// child be passed to the ancestor
if (!mCaptured) {
if (mAxes == SCROLL_AXIS_HORIZONTAL && dx != 0) {
if (HippyNestedScrollHelper.priorityOfX(target, dx) == Priority.PARENT) {
mCaptured = canScrollHorizontally(dx);
}
} else if (mAxes == SCROLL_AXIS_VERTICAL && dy != 0) {
if (HippyNestedScrollHelper.priorityOfY(target, dy) == Priority.PARENT) {
mCaptured = canScrollVertically(dy);
}
}
}
if (mCaptured) {
if (mAxes == SCROLL_AXIS_HORIZONTAL) {
fakeDragBy(-dx);
@@ -340,9 +353,13 @@ public class HippyViewPager extends ViewPager implements HippyViewBase {
// child be passed to the ancestor
if (!mCaptured) {
if (mAxes == SCROLL_AXIS_HORIZONTAL && dxUnconsumed != 0) {
mCaptured = canScrollHorizontally(dxUnconsumed);
if (HippyNestedScrollHelper.priorityOfX(target, dxUnconsumed) == Priority.SELF) {
mCaptured = canScrollHorizontally(dxUnconsumed);
}
} else if (mAxes == SCROLL_AXIS_VERTICAL && dyUnconsumed != 0) {
mCaptured = canScrollVertically(dyUnconsumed);
if (HippyNestedScrollHelper.priorityOfY(target, dyUnconsumed) == Priority.SELF) {
mCaptured = canScrollVertically(dyUnconsumed);
}
}
}
if (mCaptured) {
+42 -16
View File
@@ -129,6 +129,19 @@ Reusable vertical list function, especially suitable for data rendering of a lar
| editable | Whether it is editable or not, it needs to be set to `true` when the side slide deletion is enabled. `Minimum supported version 2.9.0` | `boolean` | `iOS` |
| delText | Slide sideways to delete text. `Minimum supported version 2.9.0` | `string` | `iOS` |
| onDelete | Called when a list item is swiped to delete. `Minimum supported version 2.9.0` | `(nativeEvent: { index: number}) => void` | `iOS` |
| nestedScrollPriority* | Nested scroll event processing priority, `default:self`. Equivalent to setting `nestedScrollLeftPriority`, `nestedScrollTopPriority`, `nestedScrollRightPriority` and `nestedScrollBottomPriority` at the same time. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollLeftPriority | Nested scroll event that **from right to left** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollTopPriority | Nested scroll event that **from bottom to top** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollRightPriority | Nested scroll event that **from left to right** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollBottomPriority | Nested scroll event that **from top to bottom** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
* Attributes meaning of nestedScrollPriority:
* `self`(default value): the current component takes priority, the scroll event will be consumed by the current component first, and the rest will be passed to the parent component for consumption;
* `parent`: the parent component takes priority, the scroll event will be consumed by the parent component first, and the rest will be consumed by the current component;
* `none`: nested scrolling is not allowed, scroll events will not be dispatched to the parent component.
## Methods
@@ -232,23 +245,36 @@ A component that wraps the platform's `ScrollView`, while also integrating a tou
## Attributes
| Props | Description | Type | Supported Platforms |
|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------|-------------------------------|
| bounces | Whether to enable the rebound effect, default`true`. | `boolean` | `iOS` |
| contentContainerStyle | These styles will be applied to an inner content container, and all subviews will be wrapped inside the content container. | `StyleSheet` | `Android、iOS、hippy-react-web、Web-Renderer` |
| horizontal | When this property is `true`, all subviews will be aligned horizontally in a row instead of the default vertical row. | `boolean` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onMomentumScrollBegin | This callback function is called when the `ScrollView` starts to slide. | `(obj: { contentOffset: { x: number, y: number } }) => any` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onMomentumScrollEnd | This callback function is called when the `ScrollView` swipe ends. | `(obj: { contentOffset: { x: number, y: number } }) => any` | `Android、iOS、hippy-react-web、Web-Renderer` |
| Props | Description | Type | Supported Platforms |
| ------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | --------------------------------------------- |
| bounces | Whether to enable the rebound effect, default`true`. | `boolean` | `iOS` |
| contentContainerStyle | These styles will be applied to an inner content container, and all subviews will be wrapped inside the content container. | `StyleSheet` | `Android、iOS、hippy-react-web、Web-Renderer` |
| horizontal | When this property is `true`, all subviews will be aligned horizontally in a row instead of the default vertical row. | `boolean` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onMomentumScrollBegin | This callback function is called when the `ScrollView` starts to slide. | `(obj: { contentOffset: { x: number, y: number } }) => any` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onMomentumScrollEnd | This callback function is called when the `ScrollView` swipe ends. | `(obj: { contentOffset: { x: number, y: number } }) => any` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onScroll | This callback function is called at most once per frame during scrolling. | `(obj: { contentOffset: { x: number, y: number } }) => any` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onScrollBeginDrag | This callback function is called when the user starts dragging the `ScrollView`. | `(obj: { contentOffset: { x: number, y: number } }) => any` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onScrollEndDrag | This callback function is called when the user stops dragging the `ScrollView` or lets go of the `ScrollView` to start sliding. | `(obj: { contentOffset: { x: number, y: number } }) => any` | `Android、iOS、hippy-react-web、Web-Renderer` |
| pagingEnabled | When `true`, the scroll bar will stop at an integer multiple of the scroll view's size. This can be used for horizontal pagination.`default: false` | `boolean` | `Android、iOS、hippy-react-web、Web-Renderer` |
| scrollEventThrottle | Specifies the callback frequency of the sliding event, and the passed value specifies how many milliseconds (ms) the component will call once the `onScroll` callback event. | `number` | `Android、iOS、hippy-react-web、Web-Renderer` |
| scrollIndicatorInsets | Determines the coordinates of the scrollbar from the edge of the view. This value should be the same as contentInset. | `{ top: number, left: number, bottom: number, right: number }` | `Android、iOS` |
| scrollEnabled | When the value is `false`, the content cannot be scrolled. `default: true` | `boolean` | `Android、iOS、hippy-react-web、Web-Renderer` |
| showScrollIndicator | Whether to display scroll bars. `default: false` | `boolean` | `Android、hippy-react-web` |
| showsHorizontalScrollIndicator | When this value is set to `false`, the horizontal scroll bar of the `ScrollView` will be hidden. `default: true` | `boolean` | `iOS` |
| showsVerticalScrollIndicator | When this value is set to `false`, the vertical scroll bar of the `ScrollView` will be hidden. `default: true` | `boolean` | `iOS` |
| onScrollBeginDrag | This callback function is called when the user starts dragging the `ScrollView`. | `(obj: { contentOffset: { x: number, y: number } }) => any` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onScrollEndDrag | This callback function is called when the user stops dragging the `ScrollView` or lets go of the `ScrollView` to start sliding. | `(obj: { contentOffset: { x: number, y: number } }) => any` | `Android、iOS、hippy-react-web、Web-Renderer` |
| pagingEnabled | When `true`, the scroll bar will stop at an integer multiple of the scroll view's size. This can be used for horizontal pagination.`default: false` | `boolean` | `Android、iOS、hippy-react-web、Web-Renderer` |
| scrollEventThrottle | Specifies the callback frequency of the sliding event, and the passed value specifies how many milliseconds (ms) the component will call once the `onScroll` callback event. | `number` | `Android、iOS、hippy-react-web、Web-Renderer` |
| scrollIndicatorInsets | Determines the coordinates of the scrollbar from the edge of the view. This value should be the same as contentInset. | `{ top: number, left: number, bottom: number, right: number }` | `Android、iOS` |
| scrollEnabled | When the value is `false`, the content cannot be scrolled. `default: true` | `boolean` | `Android、iOS、hippy-react-web、Web-Renderer` |
| showScrollIndicator | Whether to display scroll bars. `default: false` | `boolean` | `Android、hippy-react-web` |
| showsHorizontalScrollIndicator | When this value is set to `false`, the horizontal scroll bar of the `ScrollView` will be hidden. `default: true` | `boolean` | `iOS` |
| showsVerticalScrollIndicator | When this value is set to `false`, the vertical scroll bar of the `ScrollView` will be hidden. `default: true` | `boolean` | `iOS` |
| nestedScrollPriority* | Nested scroll event processing priority, `default:self`. Equivalent to setting `nestedScrollLeftPriority`, `nestedScrollTopPriority`, `nestedScrollRightPriority` and `nestedScrollBottomPriority` at the same time. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollLeftPriority | Nested scroll event that **from right to left** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollTopPriority | Nested scroll event that **from bottom to top** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollRightPriority | Nested scroll event that **from left to right** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollBottomPriority | Nested scroll event that **from top to bottom** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
* Attributes meaning of nestedScrollPriority:
* `self`(default value): the current component takes priority, the scroll event will be consumed by the current component first, and the rest will be passed to the parent component for consumption;
* `parent`: the parent component takes priority, the scroll event will be consumed by the parent component first, and the rest will be consumed by the current component;
* `none`: nested scrolling is not allowed, scroll events will not be dispatched to the parent component.
## Methods
+29 -3
View File
@@ -65,8 +65,21 @@ This component is mapped to the View component, and the container can be used to
| scrollEnabled | When the value is `false`, the content cannot scroll. `default: true` `(only applicable to overflow-y/x: scroll)` | `boolean` | `Android、iOS、Web-Renderer` |
| showScrollIndicator | Whether scroll bars are displayed. `default: false` `(only applicable to overflow-y/x: scroll)` | `boolean` | `Android` |
| showsHorizontalScrollIndicator | When set to `false`, `ScrollView` hides the horizontal scroll bar. `default: true` `(only applies to overflow-y/x: scroll)`| `boolean` | `iOS` |
| showsVerticalScrollIndicator | When set to `false`, 'ScrollView' hides the vertical scroll bar.  `default: true` `(only applicable to overflow-y/x: scroll)`| `boolean` | `iOS` |
| showsVerticalScrollIndicator | When set to `false`, 'ScrollView' hides the vertical scroll bar.  `default: true` `(only applicable to overflow-y/x: scroll)`| `boolean` | `iOS` |
| nativeBackgroundAndroid | Configure water ripple effect, `minimum supported version 2.13.1`; The configuration item is `{borderless: Boolean, color: color, rippleRadius: number}`; `Borderless` indicates whether the ripple has borders. Default is false; `color` ripple color; `rippleRadius` ripple radius, if not set, the container border is the border by default;  ` note:  The water ripple is not displayed by default. You need to call setPressed and setHotspot methods in the corresponding touch event to display the water ripple.  Details refer to the relevant `[demo](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo/src/components/demos/demo-div.vue) | `Object`| `Android` |
| nestedScrollPriority* | Nested scroll event processing priority, `default:self`. Equivalent to setting `nestedScrollLeftPriority`, `nestedScrollTopPriority`, `nestedScrollRightPriority` and `nestedScrollBottomPriority` at the same time. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollLeftPriority | Nested scroll event that **from right to left** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollTopPriority | Nested scroll event that **from bottom to top** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollRightPriority | Nested scroll event that **from left to right** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollBottomPriority | Nested scroll event that **from top to bottom** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
* Attributes meaning of nestedScrollPriority:
* `self`(default value): the current component takes priority, the scroll event will be consumed by the current component first, and the rest will be passed to the parent component for consumption;
* `parent`: the parent component takes priority, the scroll event will be consumed by the parent component first, and the rest will be consumed by the current component;
* `none`: nested scrolling is not allowed, scroll events will not be dispatched to the parent component.
---
@@ -346,15 +359,28 @@ Hippy's key features, high performance reusable list components, on the native s
| initialContentOffset | The initial offset value. In the list of initialization can specify the scroll distance, avoid flashing caused by series method of scrollT after oinitialization. Android supports after version ` 2.8.0 ` | `number` | `Android、iOS、Web-Renderer` |
| bounces | Whether to open the rebound effect, default `true` | `boolean` | `iOS` |
| overScrollEnabled | Whether to open the rebound effect, default `true` | `boolean` | `Android` |
| rowShouldSticky | Sets whether `ul` needs to turn on the hover ability, used in conjunction with `li` 's `sticky`. `default: false` | `boolean` | `Android、iOS、Web-Renderer`
| rowShouldSticky | Sets whether `ul` needs to turn on the hover ability, used in conjunction with `li` 's `sticky`. `default: false` | `boolean` | `Android、iOS、Web-Renderer`|
| scrollEnabled | Whether the slide function is on.`default: true` | `boolean` | `Android、iOS、Web-Renderer` |
| scrollEventThrottle | Specify the sliding event callback frequency, the incoming value specifies how many milliseconds (ms) components will call a `onScroll` callback event, the default is 200 ms | `number` | `Android、 iOS、Web-Renderer` |
| showScrollIndicator | Whether scroll bars are displayed. `default: true` | `boolean` | `iOS` |
| preloadItemNumber | Specifies the number of rows that will call the `endReached` function when the list scrolls.| `number` | `Android、iOS、Web-Renderer` |
| exposureEventEnabled | The switch to enable Android exposure ability, if you want to use the `appear` and `disappear` related events, Android needs to set the switch (iOS need not set), `default: true` | `boolean` | `Android`
| exposureEventEnabled | The switch to enable Android exposure ability, if you want to use the `appear` and `disappear` related events, Android needs to set the switch (iOS need not set), `default: true` | `boolean` | `Android`|
| endReached | When all the data has been rendered and the list is scrolled to the last one, the `endReached` callback is called. | `Function` | `Android、iOS、Web-Renderer` |
| editable | Whether it is editable or not, set to `true` when sideslip deletion is enabled. ` minimum support version 2.9.0 `| `boolean` | `iOS` |
| delText | Sideslip to delete text. `minimum support version 2.9.0` | `string` | `iOS` |
| nestedScrollPriority* | Nested scroll event processing priority, `default:self`. Equivalent to setting `nestedScrollLeftPriority`, `nestedScrollTopPriority`, `nestedScrollRightPriority` and `nestedScrollBottomPriority` at the same time. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollLeftPriority | Nested scroll event that **from right to left** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollTopPriority | Nested scroll event that **from bottom to top** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollRightPriority | Nested scroll event that **from left to right** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
| nestedScrollBottomPriority | Nested scroll event that **from top to bottom** processing priority, Attributes meaning is the same as `nestedScrollPriority`, this attribute has higher priority. | `enum(self,parent,none)` | `Android(minimum supported version 2.16.0)` |
* Attributes meaning of nestedScrollPriority:
* `self`(default value): the current component takes priority, the scroll event will be consumed by the current component first, and the rest will be passed to the parent component for consumption;
* `parent`: the parent component takes priority, the scroll event will be consumed by the parent component first, and the rest will be consumed by the current component;
* `none`: nested scrolling is not allowed, scroll events will not be dispatched to the parent component.
## Events
+26
View File
@@ -131,6 +131,19 @@ import icon from './qb_icon_new.png';
| editable | 是否可编辑,开启侧滑删除时需要设置为 `true`。`最低支持版本2.9.0` | `boolean` | `iOS` |
| delText | 侧滑删除文本。`最低支持版本2.9.0` | `string` | `iOS` |
| onDelete | 在列表项侧滑删除时调起。`最低支持版本2.9.0` | `(nativeEvent: { index: number}) => void` | `iOS` |
| nestedScrollPriority* | 嵌套滚动事件处理优先级,`default:self`。相当于同时设置 `nestedScrollLeftPriority`、 `nestedScrollTopPriority`、 `nestedScrollRightPriority`、 `nestedScrollBottomPriority`。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollLeftPriority | **从右往左**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollTopPriority | **从下往上**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollRightPriority | **从左往右**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollBottomPriority | **从上往下**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
* nestedScrollPriority 的参数含义:
* `self`(默认值):当前组件优先,滚动事件将先由当前组件消费,剩余部分传递给父组件消费;
* `parent`:父组件优先,滚动事件将先由父组件消费,剩余部分再由当前组件消费;
* `none`:不允许嵌套滚动,滚动事件将不会传递给父组件。
## 方法
@@ -251,6 +264,19 @@ import icon from './qb_icon_new.png';
| showScrollIndicator | 是否显示滚动条。 `default: false` | `boolean` | `Android、hippy-react-web` |
| showsHorizontalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏水平的滚动条。`default: true` | `boolean` | `iOS` |
| showsVerticalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏垂直的滚动条。 `default: true` | `boolean` | `iOS` |
| nestedScrollPriority* | 嵌套滚动事件处理优先级,`default:self`。相当于同时设置 `nestedScrollLeftPriority`、 `nestedScrollTopPriority`、 `nestedScrollRightPriority`、 `nestedScrollBottomPriority`。 | `enum(self,parent,none)` | ``Android(版本 2.16.0以上)`` |
| nestedScrollLeftPriority | **从右往左**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollTopPriority | **从下往上**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollRightPriority | **从左往右**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollBottomPriority | **从上往下**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
* nestedScrollPriority 的参数含义:
* `self`(默认值):当前组件优先,滚动事件将先由当前组件消费,剩余部分传递给父组件消费;
* `parent`:父组件优先,滚动事件将先由父组件消费,剩余部分再由当前组件消费;
* `none`:不允许嵌套滚动,滚动事件将不会传递给父组件。
## 方法
+30 -4
View File
@@ -54,7 +54,7 @@
| ------------------ | ------------------------------------------------------------ | ------------------------------------ | --------- |
| accessibilityLabel | 设置当用户与此元素交互时,“读屏器”(对视力障碍人士的辅助功能)阅读的文字。默认情况下,这个文字会通过遍历所有的子元素并累加所有的文本标签来构建。 | `string` | `Android、iOS` |
| accessible | 当此属性为 `true` 时,表示此视图时一个启用了无障碍功能的元素。默认情况下,所有可触摸操作的元素都是无障碍功能元素。 | `boolean` | `Android、iOS` |
| collapsable | 如果一个 `div` 只用于布局它的子组件,则它可能会为了优化而从原生布局树中移除,因此该节点 DOM 的引用会丢失`(比如调用 measureInAppWindow 无法获取到大小和位置信息)`。 把此属性设为 `false` 可以禁用这个优化,以确保对应视图在原生结构中存在。`(Android 2.14.1 版本后支持在 Attribute 设置,以前版本请在静态 Style 属性里设置)` | `boolean` | `Android` | | `Android` |
| collapsable | 如果一个 `div` 只用于布局它的子组件,则它可能会为了优化而从原生布局树中移除,因此该节点 DOM 的引用会丢失`(比如调用 measureInAppWindow 无法获取到大小和位置信息)`。 把此属性设为 `false` 可以禁用这个优化,以确保对应视图在原生结构中存在。`(Android 2.14.1 版本后支持在 Attribute 设置,以前版本请在静态 Style 属性里设置)` | `boolean` | `Android` |
| style | - | [`View Styles`](style/layout.md) | `Android、iOS、Web-Renderer` |
| opacity | 配置 `View` 的透明度,同时会影响子节点的透明度 | `number` | `Android、iOS、Web-Renderer` |
| overflow | 指定当子节点内容溢出其父级 `View` 容器时, 是否剪辑内容 | `enum(visible, hidden)` | `Android、iOS、Web-Renderer` |
@@ -65,8 +65,21 @@
| scrollEnabled | 当值为 `false` 的时候,内容不能滚动。`default: true` `(仅在 overflow-y/x: scroll 时适用)` | `boolean` | `Android、iOS、Web-Renderer` |
| showScrollIndicator | 是否显示滚动条。 `default: false`(仅在 overflow-y/x: scroll 时适用) | `boolean` | `Android` |
| showsHorizontalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏水平的滚动条。`default: true` `(仅在 overflow-y/x: scroll 时适用)`| `boolean` | `iOS` |
| showsVerticalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏垂直的滚动条。 `default: true` `(仅在 overflow-y/x: scroll 时适用)`| `boolean` | `iOS` |
| showsVerticalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏垂直的滚动条。 `default: true` `(仅在 overflow-y/x: scroll 时适用)`| `boolean` | `iOS` |
| nativeBackgroundAndroid | 配置水波纹效果,`最低支持版本 2.13.1`;配置项为 `{ borderless: boolean, color: Color, rippleRadius: number }`; `borderless` 表示波纹是否有边界,默认false;`color` 波纹颜色;`rippleRadius` 波纹半径,若不设置,默认容器边框为边界; `注意:设置水波纹后默认不显示,需要在对应触摸事件中调用 setPressed 和 setHotspot 方法进行水波纹展示,详情参考相关`[demo](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo/src/components/demos/demo-div.vue) | `Object`| `Android` |
| nestedScrollPriority* | 嵌套滚动事件处理优先级,`default:self`。相当于同时设置 `nestedScrollLeftPriority`、 `nestedScrollTopPriority`、 `nestedScrollRightPriority`、 `nestedScrollBottomPriority`。 | `enum(self,parent,none)` | ``Android(版本 2.16.0以上)`` |
| nestedScrollLeftPriority | **从右往左**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollTopPriority | **从下往上**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollRightPriority | **从左往右**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollBottomPriority | **从上往下**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
* nestedScrollPriority 的参数含义:
* `self`(默认值):当前组件优先,滚动事件将先由当前组件消费,剩余部分传递给父组件消费;
* `parent`:父组件优先,滚动事件将先由父组件消费,剩余部分再由当前组件消费;
* `none`:不允许嵌套滚动,滚动事件将不会传递给父组件。
---
@@ -346,15 +359,28 @@ Hippy 的重点功能,高性能的可复用列表组件,在终端侧会被
| initialContentOffset | 初始位移值。在列表初始化时即可指定滚动距离,避免初始化后再通过 scrollTo 系列方法产生的闪动。Android 在 `2.8.0` 版本后支持 | `number` | `Android、iOS、Web-Renderer` |
| bounces | 是否开启回弹效果,默认 `true` | `boolean` | `iOS` |
| overScrollEnabled | 是否开启回弹效果,默认 `true` | `boolean` | `Android` |
| rowShouldSticky | 设置 `ul` 是否需要开启悬停效果能力,与 `li` 的 `sticky` 配合使用。 `default: false` | `boolean` | `Android、iOS、Web-Renderer`
| rowShouldSticky | 设置 `ul` 是否需要开启悬停效果能力,与 `li` 的 `sticky` 配合使用。 `default: false` | `boolean` | `Android、iOS、Web-Renderer`|
| scrollEnabled | 滑动是否开启。`default: true` | `boolean` | `Android、iOS、Web-Renderer` |
| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onScroll` 回调事件,默认 200ms | `number` | `Android、iOS、Web-Renderer` |
| showScrollIndicator | 是否显示滚动条。`default: true` | `boolean` | `iOS` |
| preloadItemNumber | 指定当列表滚动至倒数第几行时触发 `endReached` 回调。 | `number` | `Android、iOS、Web-Renderer` |
| exposureEventEnabled | Android 曝光能力启用开关,如果要使用 `appear`、`disappear` 相关事件,Android 需要设置该开关(iOS无需设置), `default: true` | `boolean` | `Android`
| exposureEventEnabled | Android 曝光能力启用开关,如果要使用 `appear`、`disappear` 相关事件,Android 需要设置该开关(iOS无需设置), `default: true` | `boolean` | `Android`|
| endReached | 当所有的数据都已经渲染过,并且列表被滚动到最后一条时,将触发 `endReached` 回调。 | `Function` | `Android、iOS、Web-Renderer` |
| editable | 是否可编辑,开启侧滑删除时需要设置为 `true`。`最低支持版本2.9.0` | `boolean` | `iOS` |
| delText | 侧滑删除文本。`最低支持版本2.9.0` | `string` | `iOS` |
| nestedScrollPriority* | 嵌套滚动事件处理优先级,`default:self`。相当于同时设置 `nestedScrollLeftPriority`、 `nestedScrollTopPriority`、 `nestedScrollRightPriority`、 `nestedScrollBottomPriority`。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollLeftPriority | **从右往左**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollTopPriority | **从下往上**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollRightPriority | **从左往右**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
| nestedScrollBottomPriority | **从上往下**的嵌套滚动事件的处理优先级,参数含义同`nestedScrollPriority`,此参数优先级更高。 | `enum(self,parent,none)` | `Android(版本 2.16.0以上)` |
* nestedScrollPriority 的参数含义:
* `self`(默认值):当前组件优先,滚动事件将先由当前组件消费,剩余部分传递给父组件消费;
* `parent`:父组件优先,滚动事件将先由父组件消费,剩余部分再由当前组件消费;
* `none`:不允许嵌套滚动,滚动事件将不会传递给父组件。
## 事件
@@ -0,0 +1,126 @@
import React from 'react';
import {
ListView,
View,
StyleSheet,
Text,
ViewPager,
ScrollView,
} from '@hippy/react';
const styles = StyleSheet.create({
demoWrap: {
horizontal: false,
flex: 1,
flexDirection: 'column',
},
banner: {
backgroundImage: 'https://user-images.githubusercontent.com/12878546/148736102-7cd9525b-aceb-41c6-a905-d3156219ef16.png',
backgroundSize: 'cover',
height: 150,
justifyContent: 'flex-end',
},
bannerText: {
color: 'coral',
textAlign: 'center',
},
tabs: {
flexDirection: 'row',
height: 30,
},
tabText: {
flex: 1,
textAlign: 'center',
backgroundColor: '#eee',
color: '#999',
},
tabSelected: {
flex: 1,
textAlign: 'center',
color: '#4c9afa',
},
itemEven: {
height: 40,
backgroundColor: 'gray',
},
itemEvenText: {
lineHeight: 40,
color: 'white',
fontSize: 25,
textAlign: 'center',
},
itemOdd: {
height: 40,
},
itemOddText: {
lineHeight: 40,
fontSize: 25,
textAlign: 'center',
},
});
export default class NestedScrollExample extends React.Component {
constructor(props) {
super(props);
this.state = {
layoutHeight: 0,
bannerHeight: 80,
currentSlide: 0,
};
}
selectPage(i) {
this.setState({ currentSlide: i });
this.viewPager?.setPage(i);
}
render() {
const { layoutHeight, bannerHeight, currentSlide } = this.state;
console.log('currentSlide', currentSlide);
return (
<ScrollView
style={styles.demoWrap}
scrollEventThrottle={50}
onLayout={e => this.setState({ layoutHeight: e.layout.height })}
onScroll={e => this.setState({ bannerHeight: Math.min(150 - e.contentOffset.y, 80) })}>
<View style={styles.banner}>
<Text style={[styles.bannerText, { height: bannerHeight, fontSize: bannerHeight }]}>
Banner
</Text>
</View>
<View style={styles.tabs}>
<Text
key="tab1"
style={(currentSlide === 0) ? styles.tabSelected : styles.tabText}
onClick={() => this.selectPage(0)}>
tab 1
</Text>
<Text
key="tab2"
style={(currentSlide === 1) ? styles.tabSelected : styles.tabText}
onClick={() => this.selectPage(1)}>
tab 2
</Text>
</View>
<ViewPager
ref={ref => this.viewPager = ref}
initialPage={currentSlide}
style={{ height: layoutHeight - 80 }}
onPageSelected={e => this.setState({ currentSlide: e.position })}>
<ListView nestedScrollTopPriority="parent" key="slide1"
numberOfRows={30}
getRowKey={i => `item${i}`}
renderRow={i => (
<Text style={i % 2 ? styles.itemEvenText : styles.itemOddText}>Item {i}</Text>
)}
getRowStyle={i => (i % 2 ? styles.itemEven : styles.itemOdd)}
/>
<View key="slide2" style={{ flex: 1, justifyContent: 'space-around' }}>
<Text style={{ textAlign: 'center' }}>
I&apos;m Slide 2
</Text>
</View>
</ViewPager >
</ScrollView >);
}
}
+1
View File
@@ -6,3 +6,4 @@ export { default as SetNativeProps } from './SetNativeProps';
export { default as DynamicImport } from './DyanmicImport';
export { default as Localization } from './Localization';
export { default as Turbo } from './Turbo';
export { default as NestedScroll } from './NestedScroll';
+8
View File
@@ -129,6 +129,14 @@ export default [
style: 1,
},
},
{
path: '/NestedScroll',
name: 'Nested Scroll 示例',
component: PAGE_LIST.NestedScroll,
meta: {
style: 1,
},
},
{
path: '/WebView',
name: 'WebView 组件',
@@ -0,0 +1,142 @@
<template>
<div
id="demo-wrap"
scrollEventThrottle="50"
@layout="onlayout"
@scroll="onscroll"
>
<div id="demo-content">
<div id="banner">
<p :style="{ height: bannerHeight, 'font-size': bannerHeight, }">
Banner
</p>
</div>
<div id="tabs">
<p
v-for="n in 2"
:key="('tab' + n)"
:class="(currentSlide === n - 1) ? 'selected' : ''"
@click="ontabclick(n)"
>
tab {{ n }}
</p>
</div>
<swiper
id="swiper"
ref="swiper"
need-animation
:current="currentSlide"
:style="{ height: layoutHeight - 80 }"
@dropped="ondropped"
>
<!-- slides -->
<swiper-slide key="slide1">
<ul nestedScrollTopPriority="parent">
<li
v-for="n in 30"
:key="('item' + n)"
:class="(n % 2) ? 'item-even' : 'item-odd'"
>
<p>Item {{ n }}</p>
</li>
</ul>
</swiper-slide>
<swiper-slide key="slide2">
<div style="flex: 1; justify-content: space-around">
<p style="text-align: center">
I'm Slide 2
</p>
</div>
</swiper-slide>
</swiper>
</div>
</div>
</template>
<script>
export default {
data() {
return {
layoutHeight: 0,
bannerHeight: 80,
currentSlide: 0,
};
},
methods: {
onlayout(e) {
this.layoutHeight = e.height;
},
onscroll(e) {
this.bannerHeight = Math.min(150 - e.offsetY, 80);
},
ontabclick(i) {
console.log('onclick', i);
this.currentSlide = i - 1;
},
ondropped(e) {
this.currentSlide = e.currentSlide;
},
},
};
</script>
<style scoped>
#demo-wrap {
overflow-y: scroll;
flex: 1;
}
#demo-content {
flex-direction: column;
}
#banner {
background-image: url(https://user-images.githubusercontent.com/12878546/148736102-7cd9525b-aceb-41c6-a905-d3156219ef16.png);
background-size: cover;
height: 150;
justify-content: flex-end;
}
#banner p {
color: coral;
text-align: center;
}
#tabs {
flex-direction: row;
height: 30;
}
#tabs p {
flex: 1;
text-align: center;
background-color: #eee;
}
#tabs .selected {
background-color: white;
color: #40b883;
}
.item-even {
height: 40;
}
.item-even p {
line-height: 40;
font-size: 25;
text-align: center;
}
.item-odd {
height: 40;
background-color: gray;
}
.item-odd p {
line-height: 40;
color: white;
font-size: 25;
text-align: center;
}
</style>
@@ -6,6 +6,7 @@ import demoDialog from './demo-dialog.vue';
import demoSwiper from './demo-swiper.vue';
import demoPullHeaderFooter from './demo-pull-header-footer.vue';
import demoWaterfall from './demo-waterfall.vue';
import demoNestedScroll from './demo-nested-scroll.vue';
const demos = {};
@@ -39,6 +40,10 @@ if (Vue.Native) {
name: 'setNativeProps',
component: demoSetNativeProps,
},
demoNestedScroll: {
name: 'Nested Scroll 示例',
component: demoNestedScroll,
},
});
}
@@ -0,0 +1,142 @@
<template>
<div
id="demo-wrap"
scrollEventThrottle="50"
@layout="onlayout"
@scroll="onscroll"
>
<div id="demo-content">
<div id="banner">
<p :style="{ height: bannerHeight, 'font-size': bannerHeight, }">
Banner
</p>
</div>
<div id="tabs">
<p
v-for="n in 2"
:key="('tab' + n)"
:class="(currentSlide === n - 1) ? 'selected' : ''"
@click="ontabclick(n)"
>
tab {{ n }}
</p>
</div>
<swiper
id="swiper"
ref="swiper"
need-animation
:current="currentSlide"
:style="{ height: layoutHeight - 80 }"
@dropped="ondropped"
>
<!-- slides -->
<swiper-slide key="slide1">
<ul nestedScrollTopPriority="parent">
<li
v-for="n in 30"
:key="('item' + n)"
:class="(n % 2) ? 'item-even' : 'item-odd'"
>
<p>Item {{ n }}</p>
</li>
</ul>
</swiper-slide>
<swiper-slide key="slide2">
<div style="flex: 1; justify-content: space-around">
<p style="text-align: center">
I'm Slide 2
</p>
</div>
</swiper-slide>
</swiper>
</div>
</div>
</template>
<script lang="ts">
export default {
data() {
return {
layoutHeight: 0,
bannerHeight: 80,
currentSlide: 0,
};
},
methods: {
onlayout(e) {
this.layoutHeight = e.height;
},
onscroll(e) {
this.bannerHeight = Math.min(150 - e.offsetY, 80);
},
ontabclick(i) {
console.log('onclick', i);
this.currentSlide = i - 1;
},
ondropped(e) {
this.currentSlide = e.currentSlide;
},
},
};
</script>
<style scoped>
#demo-wrap {
overflow-y: scroll;
flex: 1;
}
#demo-content {
flex-direction: column;
}
#banner {
background-image: url(https://user-images.githubusercontent.com/12878546/148736102-7cd9525b-aceb-41c6-a905-d3156219ef16.png);
background-size: cover;
height: 150;
justify-content: flex-end;
}
#banner p {
color: coral;
text-align: center;
}
#tabs {
flex-direction: row;
height: 30;
}
#tabs p {
flex: 1;
text-align: center;
background-color: #eee;
}
#tabs .selected {
background-color: white;
color: #40b883;
}
.item-even {
height: 40;
}
.item-even p {
line-height: 40;
font-size: 25;
text-align: center;
}
.item-odd {
height: 40;
background-color: gray;
}
.item-odd p {
line-height: 40;
color: white;
font-size: 25;
text-align: center;
}
</style>
@@ -5,6 +5,7 @@ import demoVueNative from './demo-vue-native.vue';
import demoPullHeaderFooter from './demo-pull-header-footer.vue';
import demoSwiper from './demo-swiper.vue';
import demoWaterfall from './demo-waterfall.vue';
import demoNestedScroll from './demo-nested-scroll.vue';
const demos = {
demoNative: {
@@ -35,6 +36,10 @@ const demos = {
name: 'setNativeProps',
component: demoSetNativeProps,
},
demoNestedScroll: {
name: 'nested scroll 示例',
component: demoNestedScroll,
},
};
export default demos;