ion-content scrollto会触发ion content 滚动事件件吗

44129人阅读
Android 高手进阶(21)
转帖请注明本文出自xiaanming的博客(),请尊重他人的辛勤劳动成果,谢谢!今天给大家讲解的是Scroller类的滚动实现原理,可能很多朋友不太了解该类是用来干嘛的,但是研究Launcher的朋友应该对他很熟悉,Scroller类是滚动的一个封装类,可以实现View的平滑滚动效果,什么是实现View的平滑滚动效果呢,举个简单的例子,一个View从在我们指定的时间内从一个位置滚动到另外一个位置,我们利用Scroller类可以实现匀速滚动,可以先加速后减速,可以先减速后加速等等效果,而不是瞬间的移动的效果,所以Scroller可以帮我们实现很多滑动的效果。在介绍Scroller类之前,我们先去了解View的scrollBy() 和scrollTo()方法的区别,在区分这两个方法的之前,我们要先理解View 里面的两个成员变量mScrollX, mScrollY,X轴方向的偏移量和Y轴方向的偏移量,这个是一个相对距离,相对的不是屏幕的原点,而是View的左边缘,举个通俗易懂的例子,一列火车从吉安到深圳,途中经过赣州,那么原点就是赣州,偏移量就是 负的吉安到赣州的距离,大家从getScrollX()方法中的注释中就能看出答案来 /**
* Return the scrolled left position of this view. This is the left edge of
* the displayed part of your view. You do not need to draw any pixels
* farther left, since those are outside of the frame of your view on
* @return The left edge of the displayed part of your view, in pixels.
public final int getScrollX() {
return mScrollX;
}现在我们知道了向右滑动 mScrollX就为负数,向左滑动mScrollX为正数,接下来我们先来看看&scrollTo()方法的源码
* Set the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the x position to scroll to
* @param y the y position to scroll to
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX =
mScrollY =
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
invalidate();
}从该方法中我们可以看出,先判断传进来的(x, y)值是否和View的X, Y偏移量相等,如果不相等,就调用onScrollChanged()方法来通知界面发生改变,然后重绘界面,所以这样子就实现了移动效果啦, 现在我们知道了scrollTo()方法是滚动到(x, y)这个偏移量的点,他是相对于View的开始位置来滚动的。在看看scrollBy()这个方法的代码 /**
* Move the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the amount of pixels to scroll by horizontally
* @param y the amount of pixels to scroll by vertically
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}原来他里面调用了scrollTo()方法,那就好办了,他就是相对于View上一个位置根据(x, y)来进行滚动,可能大家脑海中对这两个方法还有点模糊,没关系,还是举个通俗的例子帮大家理解下,假如一个View,调用两次scrollTo(-10, 0),第一次向右滚动10,第二次就不滚动了,因为mScrollX和x相等了,当我们调用两次scrollBy(-10, 0),第一次向右滚动10,第二次再向右滚动10,他是相对View的上一个位置来滚动的。对于scrollTo()和scrollBy()方法还有一点需要注意,这点也很重要,假如你给一个LinearLayout调用scrollTo()方法,并不是LinearLayout滚动,而是LinearLayout里面的内容进行滚动,比如你想对一个按钮进行滚动,直接用Button调用scrollTo()一定达不到你的需求,大家可以试一试,如果真要对某个按钮进行scrollTo()滚动的话,我们可以在Button外面包裹一层Layout,然后对Layout调用scrollTo()方法。了解了scrollTo()和scrollBy()方法之后我们就了解下Scroller类了,先看其构造方法
* Create a Scroller with the default duration and interpolator.
public Scroller(Context context) {
this(context, null);
* Create a Scroller with the specified interpolator. If the interpolator is
* null, the default (viscous) interpolator will be used.
public Scroller(Context context, Interpolator interpolator) {
mFinished =
mInterpolator =
float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
mDeceleration = SensorManager.GRAVITY_EARTH
// g (m/s^2)
// inch/meter
// pixels per inch
* ViewConfiguration.getScrollFriction();
}只有两个构造方法,第一个只有一个Context参数,第二个构造方法中指定了Interpolator,什么Interpolator呢?中文意思插补器,了解Android动画的朋友都应该熟悉Interpolator,他指定了动画的变化率,比如说匀速变化,先加速后减速,正弦变化等等,不同的Interpolator可以做出不同的效果出来,第一个使用默认的Interpolator(viscous)&接下来我们就要在Scroller类里面找滚动的方法,我们从名字上面可以看出startScroll()应该是个滚动的方法,我们来看看其源码吧
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished =
mDuration =
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX +
mFinalY = startY +
mDurationReciprocal = 1.0f / (float) mD
// This controls the viscous fluid effect (how much of it)
mViscousFluidScale = 8.0f;
// must be set to 1.0 (used in viscousFluid())
mViscousFluidNormalize = 1.0f;
mViscousFluidNormalize = 1.0f / viscousFluid(1.0f);
}在这个方法中我们只看到了对一些滚动的基本设置动作,比如设置滚动模式,开始时间,持续时间等等,并没有任何对View的滚动操作,也许你正纳闷,不是滚动的方法干嘛还叫做startScroll(),稍安勿躁,既然叫开始滚动,那就是对滚动的滚动之前的基本设置咯。
* Call this when you want to know the new location.
If it returns true,
* the animation is not yet finished.
loc will be altered to provide the
* new location.
public boolean computeScrollOffset() {
if (mFinished) {
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed & mDuration) {
switch (mMode) {
case SCROLL_MODE:
float x = (float)timePassed * mDurationR
if (mInterpolator == null)
x = viscousFluid(x);
x = mInterpolator.getInterpolation(x);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
case FLING_MODE:
float timePassedSeconds = timePassed / 1000.0f;
float distance = (mVelocity * timePassedSeconds)
- (mDeceleration * timePassedSeconds * timePassedSeconds / 2.0f);
mCurrX = mStartX + Math.round(distance * mCoeffX);
// Pin to mMinX &= mCurrX &= mMaxX
mCurrX = Math.min(mCurrX, mMaxX);
mCurrX = Math.max(mCurrX, mMinX);
mCurrY = mStartY + Math.round(distance * mCoeffY);
// Pin to mMinY &= mCurrY &= mMaxY
mCurrY = Math.min(mCurrY, mMaxY);
mCurrY = Math.max(mCurrY, mMinY);
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished =
}我们在startScroll()方法的时候获取了当前的动画毫秒赋值给了mStartTime,在computeScrollOffset()中再一次调用AnimationUtils.currentAnimationTimeMillis()来获取动画毫秒减去mStartTime就是持续时间了,然后进去if判断,如果动画持续时间小于我们设置的滚动持续时间mDuration,进去switch的SCROLL_MODE,然后根据Interpolator来计算出在该时间段里面移动的距离,赋值给mCurrX, mCurrY, 所以该方法的作用是,计算在0到mDuration时间段内滚动的偏移量,并且判断滚动是否结束,true代表还没结束,false则表示滚动介绍了,Scroller类的其他的方法我就不提了,大都是一些get(), set()方法。看了这么多,到底要怎么才能触发滚动,你心里肯定有很多疑惑,在说滚动之前我要先提另外一个方法computeScroll(),该方法是滑动的控制方法,在绘制View时,会在draw()过程调用该方法。我们先看看computeScroll()的源码 /**
* Called by a parent to request that a child update its values for mScrollX
* and mScrollY if necessary. This will typically be done if the child is
* animating a scroll using a {@link android.widget.Scroller Scroller}
public void computeScroll() {
}没错,他是一个空的方法,需要子类去重写该方法来实现逻辑,到底该方法在哪里被触发呢。我们继续看看View的绘制方法draw() public void draw(Canvas canvas) {
final int privateFlags = mPrivateF
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
1. Draw the background
2. If necessary, save the canvas' layers to prepare for fading
3. Draw view's content
4. Draw children
5. If necessary, draw the fading edges and restore layers
6. Draw decorations (scrollbars for instance)
// Step 1, draw the background, if needed
if (!dirtyOpaque) {
final Drawable background = mB
if (background != null) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
if (mBackgroundSizeChanged) {
background.setBounds(0, 0,
mRight - mLeft, mBottom - mTop);
mBackgroundSizeChanged =
if ((scrollX | scrollY) == 0) {
background.draw(canvas);
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
// skip step 2 & 5 if possible (common case)
final int viewFlags = mViewF
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// Step 3, draw the content
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 6, draw decorations (scrollbars)
onDrawScrollBars(canvas);
// we're done...
......我们只截取了draw()的部分代码,这上面11-16行为我们写出了绘制一个View的几个步骤,我们看看第四步绘制孩子的时候会触发dispatchDraw()这个方法,来看看源码是什么内容 /**
* Called by draw to draw the child views. This may be overridden
* by derived classes to gain control just before its children are drawn
* (but after its own view has been drawn).
* @param canvas the canvas on which to draw the view
protected void dispatchDraw(Canvas canvas) {
}好吧,又是定义的一个空方法,给子类来重写的方法,所以我们找到View的子类ViewGroup来看看该方法的具体实现逻辑
protected void dispatchDraw(Canvas canvas) {
final int count = mChildrenC
final View[] children = mC
int flags = mGroupF
if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
final boolean buildCache = !isHardwareAccelerated();
for (int i = 0; i & i++) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
final LayoutParams params = child.getLayoutParams();
attachLayoutAnimationParameters(child, params, i, count);
bindLayoutAnimation(child);
if (cache) {
child.setDrawingCacheEnabled(true);
if (buildCache) {
child.buildDrawingCache(true);
final LayoutAnimationController controller = mLayoutAnimationC
if (controller.willOverlap()) {
mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
controller.start();
mGroupFlags &= ~FLAG_RUN_ANIMATION;
mGroupFlags &= ~FLAG_ANIMATION_DONE;
if (cache) {
mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
if (mAnimationListener != null) {
mAnimationListener.onAnimationStart(controller.getAnimation());
int saveCount = 0;
final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
if (clipToPadding) {
saveCount = canvas.save();
canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
mScrollX + mRight - mLeft - mPaddingRight,
mScrollY + mBottom - mTop - mPaddingBottom);
// We will draw our child's animation, let's reset the flag
mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
boolean more =
final long drawingTime = getDrawingTime();
if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
for (int i = 0; i & i++) {
final View child = children[i];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
more |= drawChild(canvas, child, drawingTime);
for (int i = 0; i & i++) {
final View child = children[getChildDrawingOrder(count, i)];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
more |= drawChild(canvas, child, drawingTime);
// Draw any disappearing views that have animations
if (mDisappearingChildren != null) {
final ArrayList&View& disappearingChildren = mDisappearingC
final int disappearingCount = disappearingChildren.size() - 1;
// Go backwards -- we may delete as animations finish
for (int i = disappearingC i &= 0; i--) {
final View child = disappearingChildren.get(i);
more |= drawChild(canvas, child, drawingTime);
if (debugDraw()) {
onDebugDraw(canvas);
if (clipToPadding) {
canvas.restoreToCount(saveCount);
// mGroupFlags might have been updated by drawChild()
flags = mGroupF
if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
invalidate(true);
if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
mLayoutAnimationController.isDone() && !more) {
// We want to erase the drawing cache and notify the listener after the
// next frame is drawn because one extra invalidate() is caused by
// drawChild() after the animation is over
mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
final Runnable end = new Runnable() {
public void run() {
notifyAnimationListener();
post(end);
}这个方法代码有点多,但是我们还是挑重点看吧,从65-79行可以看出 在dispatchDraw()里面会对ViewGroup里面的子View调用drawChild()来进行绘制,接下来我们来看看drawChild()方法的代码 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
(child.mPrivateFlags & DRAW_ANIMATION) == 0) {
puteScroll();
final int sx = child.mScrollX;
final int sy = child.mScrollY;
boolean scalingRequired =
Bitmap cache =
}只截取了部分代码,看到puteScroll()你大概明白什么了吧,转了老半天终于找到了computeScroll()方法被触发,就是ViewGroup在分发绘制自己的孩子的时候,会对其子View调用computeScroll()方法整理下思路,来看看View滚动的实现原理,我们先调用Scroller的startScroll()方法来进行一些滚动的初始化设置,然后迫使View进行绘制,我们调用View的invalidate()或postInvalidate()就可以重新绘制View,绘制View的时候会触发computeScroll()方法,我们重写computeScroll(),在computeScroll()里面先调用Scroller的computeScrollOffset()方法来判断滚动有没有结束,如果滚动没有结束我们就调用scrollTo()方法来进行滚动,该scrollTo()方法虽然会重新绘制View,但是我们还是要手动调用下invalidate()或者postInvalidate()来触发界面重绘,重新绘制View又触发computeScroll(),所以就进入一个循环阶段,这样子就实现了在某个时间段里面滚动某段距离的一个平滑的滚动效果也许有人会问,干嘛还要调用来调用去最后在调用scrollTo()方法,还不如直接调用scrollTo()方法来实现滚动,其实直接调用是可以,只不过scrollTo()是瞬间滚动的,给人的用户体验不太好,所以Android提供了Scroller类实现平滑滚动的效果。为了方面大家理解,我画了一个简单的调用示意图好了,讲到这里就已经讲完了Scroller类的滚动实现原理啦,不知道大家理解了没有,Scroller能实现很多滚动的效果,由于考虑到这篇文章的篇幅有点长,所以这篇文章就不带领大家来使用Scroller类了,我将在下一篇文章将会带来Scroller类的使用,希望大家到时候关注下,有疑问的同学在下面留言,我会为大家解答的!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:3598644次
积分:18463
积分:18463
排名:第366名
原创:60篇
转载:15篇
评论:4164条
Android 技术讨论群
我的联系方式
文章:15篇
阅读:594160
(3)(1)(1)(1)(1)(3)(4)(4)(2)(2)(5)(6)(10)(8)(15)(4)(2)(1)(2)ionic js 指令布局介绍
(window.slotbydup=window.slotbydup || []).push({
id: '2611110',
container: s,
size: '240,200',
display: 'inlay-fix'
您当前位置: &
[ 所属分类
作者 红领巾 ]
学习要点:1. 标题栏 : ion-header-bar2. 页脚栏 : ion-footer-bar3. header/footer : 样式及内容4. 内容区 : ion-content5. 滚动框 : ion-scroll6. 下拉更新数据 : ion-refresher7. 上拉更新数据 : ion-infinite-scroll8. 脚本接口 : $ionicScrollDelegate1. 标题栏 : ion-header-barion-header-bar 指令声明一个标题栏元素,标题栏总是位于屏幕的顶部:&ion-header-bar&...&/ion-header-bar&ion-header-bar 指令有两个可选的属性:align-title - 设置标题文字的对齐方式。允许值: left | right | center,分别对应左对齐、 右对齐和居中对齐。no-tap-scroll - 当点击标题时,是否将内容区域自动滚动到最开始。允许值: true |false,默认为 false。用法:&ion-header-bar align-title="left" class="bar-positive"&&div class="buttons"&&button class="button" ng-click="doSomething()"&左侧按钮&/button&&/div&&h1 class="title"&Title!&/h1&&div class="buttons"&&button class="button"&右侧按钮&/button&&/div&&/ion-header-bar&&ion-content&一些内容!&/ion-content&2. 页脚栏 : ion-footer-barion-footer-bar 指令声明一个页脚栏元素,页脚栏总是位于屏幕的底部:&ion-footer-bar&...&/ion-footer-bar&ion-footer-bar 指令有一个可选的属性:align-title - 设置标题文本的对齐方式。允许值: left | right | center 。 现在好像没有作用&ion-content&一些内容!&/ion-content&&ion-footer-bar align-title="left" class="bar-assertive"&&div class="buttons"&&button class="button"&左侧按钮&/button&&/div&&h1 class="title"&Title!&/h1&&div class="buttons" ng-click="doSomething()"&&button class="button"&右侧按钮&/button&&/div&&/ion-footer-bar&3. header/footer : 样式及内容ion-header-bar 和 ion-footer-bar 经过编译后其样式类将分别被设置为.bar.bar-header和.bar.bar-footer,回忆下我们在 CSS 框架课程中已经了解到的内容:显然,你可以使用这些样式调整 ion-header-bar/ion-footer-bar 的外观!4. 内容区 : ion-content使用 ion-content 指令定义内容区域:&ion-content&...&/ion-content&ion-content 占据 header 和 footer 以外的剩余区域。当内容超过可视区域时, ion-content可以滚动以显示被隐藏的部分。试着滚动右边示例效果的内容区域,你会发现浮现的滚动条。当滚动停止时,浮动条消失。这是 ionic 定制的滚动视图,可以使用 overflow-scroll 属性设置使用系统内置的滚动条:&ion-content overflow-scroll="true"&...&/ion-content&scroll="false" 禁止滚动 用于百度地图 或者谷歌地图显示&ion-content scroll="false" &...&/ion-content&5. ionic 滚动框 : ion-scrollion-scroll 指令声明一个可滚动的容器元素,用户可以按住内容进行拖动:&ion-scroll&&!--content--&&/ion-scroll&ion-scroll 指令有两个常用的可选属性:direction - 内容可以滚动的方向。允许值: x|y|xy。默认为 y。zooming - 是否支持 pinch-to-zoom(捏拉缩放)。允许值: true | false。在使用 ion-scroll 时,需要显式指定滚动框元素及内容元素 的大小(高度和宽度):6. 下拉更新数据 : ion-refresher使用指令 ion-refresher 可以为滚动容器( ion-scroll 或 ion-content)增加 拉动刷新/pull-to-refresh 的功能:&ion-refresher&&/ion-refresher&ion-refresher 指令有以下可选的属性:on-refresh - 当用户向下拉动足够的距离并松开时,执行此表达式on-pulling - 当用户开始向下拉动时,执行此表达式pulling-text - 当用户向下拉动时,显示此文本pulling-icon - 当用户向下拉动时,显示此图标refreshing-icon - 当用户向下拉动并松开后,显示的等待图标。 ionic 推荐使用spinner 代替这个属性spinner - 和 refreshing-icon 的作用一样,但 spinner 是基于 SVG 的动画disable-pulling-rotation - 禁止下拉图标旋转动画注意在刷新完毕后,应当使用作用域的$broadcast()方法通知框架:$scope.$broadcast("scoll.refreshComplete")spinner 使用:&ion-infinite-scroll on-infinite="load_more();" spinner="android"&&/ion-infinite-scroll&/docs/api/directive/ionSpinner/7. 上拉更新数据 : ion-infinite-scroll使用 ion-infinite-scroll 指令可以为滚动容器( ion-scroll 或 ion-content)增加 滚动刷新功能:&ion-infinite-scroll on-infinite=""&...&/ion-infinite-scroll&ion-infinite-scroll 指令有如下属性:on-infinite - 必须。当滚动到底部时执行此表达式distance - 可选。距底部距离百分比。当距离底部超过此数值时,执行 on-infinite。默认为 1%icon - 可选。载入时显示的图标。默认是 ion-load-d。 ionic 推荐使用 spinner代替 icon 属性spinner - 可选。载入时的 spinner。默认是 ionSpinnerimmediate-check - 可选。是否在载入时立即检查滚动框范围载入图标使用 icon 属性设置为 ion-load-a 试试8. $ionicScrollDelegate 指令可以使用服务$ionicScrollDelegate,通过脚本控制滚动容器( ion-scroll 或 ion-content)。$ionicScrollDelegate 服务提供的常用方法如下:resize()重新计算容器尺寸。当父元素大小变化时,应当调用此方法scrollTop([shouldAnimate])滚动到内容顶部。 shouldAnimate 参数为 true|false,表示是否使用动画展示滚动过程scrollBottom([shouldAnimate])滚动到内容底部。 shouldAnimate 参数为 true|false,表示是否使用动画展示滚动过程scrollTo(left,top[,shouldAnimate])滚动到指定位置。 left 和 top 分别表示要滚动到的 x 坐标和 y 坐标scrollBy(left,top[,shouldAnimate])滚动指定偏移量。 left 和 top 分别表示要滚动的 x 偏移量和 y 偏移量getScrollPosition()读取当前视图位置。返回值为一个 JSON 对象,具有 left 和 top 属性,分别表示 x 和 y 坐标angular.module("myAPP",["ionic"]).controller("firstCtrl",["$scope","$ionicScrollDelegate",function($scope,$ionicScollDelegate){$scope.items = [];for(var i=0;i&100;i++)$scope.items.push(["item ",i+1].join(""));$scope.gotop = function(){$ionicScollDelegate.scrollTop(true);}$scope.gobottom = function(){$ionicScollDelegate.scrollBottom(true);}}]);
本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程
转载请注明本文标题:本站链接:
分享请点击:
1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
阅读(3251)
CodeSecTeam微信公众号
总有人在你切一盘水果时秒杀一道数学题,总有人在你调整愤怒的小鸟弹射角度时记住一个单词,总有人在你打一盘dota的时间内看完一章教材,总有人在你打一局2K的时间里完成一套阅读题,总有人在你与他人闲聊时听一段VOA,总有人在你熟睡时回想一天的得失,总有人比你跑得快,你还会虚度光阴么?
手机客户端
,专注代码审计及安全周边编程,转载请注明出处:http://www.codesec.net
转载文章如有侵权,请邮件 admin[at]codesec.net}

我要回帖

更多关于 ion content 无法滚动 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信