ViewDragHelper源码分析

Android修炼系列(十一),强大的可拖拽工具类ViewDragHelper 其中ViewDragCallback是我自己创建的内部类,继承自ViewDragHelper.Callback实现类。@Override// 决定child是否可以被拖拽,具体见下文源码分析@Override// 可决定child横向的偏移计算,见下文@Override// 可决定child竖向的偏移计算,见下文return top; 阅读详情

ViewDragHelper的源码分析

注1:本文内容纯作者手打原创,如需转载请注明出处。

注2:作者目前在找工作,初级安卓工程师的水平如有需要的请留言或私信,万分感谢。

开篇

先说一下为什么会关注到这个类,也许好多人都没听过这个是干嘛的,不过对于DrawerLayout大家应该都很熟悉,是官方出的一个用于实现抽屉效果的布局控件,虽然在效果上可能没有SlidingMenu炫,不过胜在简单好用,而DrawerLayout的底层拖动就是由ViewDragHelper来实现的,顾名思义就知道是一个View的拖动帮助类,其实这个类是在android2.0的时候就存在了,不过关注度真的好低,直到DrawerLayout出现,大家才注意到有这么个能能够非常方便的帮助我能去实现各种View的拖动和边缘的检测。
特别感谢郭神,姜糖水,还有一位没有署名的作者的帮助。文末会有相应的连接。写的都太棒了。

基本使用

ViewDragHelper对象的构建通常在viewGroup的内部,用于实现一个自定义的布局的时候,对布局内部的View进行拖动,可用的构造方法有两种。

/**
 * 两个工厂方法,通常使用第一个
 * forParent 表示所在的ViewGroup
 * sensitivity 表示拖动的灵敏度
 * cb 表示我们需要实现的拖动的各种监听
 * */
public static ViewDragHelper create(ViewGroup forParent, Callback cb) {
    return new ViewDragHelper(forParent.getContext(), forParent, cb);
}

public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) {
    final ViewDragHelper helper = create(forParent, cb);
    helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));
    return helper;
}
//这个是在父View的构造方法中进行实例化。
public MyLinearLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    initView();
}

private void initView() {
    mHelper=ViewDragHelper.create(this, new myCallBack());
}

其中mTouchSlop为能够被系统识别为滑动的移动距离。两个构建方法并不难,我们继续,看下在ViewGroup中还需要做些什么。

 /**
 * Check if this event as provided to the parent view's onInterceptTouchEvent should
 * cause the parent to intercept the touch event stream.
 *检测这个作为被提供给父view的onInterceptTouchEvent的事件是否令父view拦截到当前的触摸事件流.
 * @param ev MotionEvent provided to onInterceptTouchEvent
 * 如果父View在onInterceptTouchEvent方法中应该返回true的话, 则返回true
 * 意思就是如果父控件决定拦截,就返回true。
 * @return true if the parent view should return true from onInterceptTouchEvent
 */
public boolean shouldInterceptTouchEvent(MotionEvent ev) {}

后面的代码实在是太多就没有全贴,我们只需要知道这个方法是使用就一个了,当然还是推荐大家去看一下里面都做了什么,便于更好的理解和使用这个类。shouldInterceptTouchEvent()方法在ViewGroup的onInterceptTouchEvent()方法中调用,直接把事件传过去,跟GestureDetector用法差不多。接下来还有。

   /**
 * Process a touch event received by the parent view. This method will dispatch callback events
 * as needed before returning. The parent view's onTouchEvent implementation should call this.
 *  处理从父view中获取的触摸事件.这个方法将分发callback回调事件.父view的onTouchEvent方法中应该调用该方法.
 * @param ev The touch event received by the parent view
 */
public void processTouchEvent(MotionEvent ev) {}

processTouchEvent则在父View的onTouchEvent方法中被调用,用于分发CallBack的回调事件。
onInterceptTouchEvent中通过使用mHelper.shouldInterceptTouchEvent(event)来决定我们是否应该拦截当前的事件。onTouchEvent中通过mHelper.processTouchEvent(event)处理事件。(来自郭神博客)

/**
 * Move the captured settling view by the appropriate amount for the current time.
 * If <code>continueSettling</code> returns true, the caller should call it again
 * on the next frame to continue.
 *
 * @param deferCallbacks true if state callbacks should be deferred via posted message.
 *                       Set this to true if you are calling this method from
 *                       {@link android.view.View#computeScroll()} or similar methods
 *                       invoked as part of layout or drawing.
 * @return true if settle is still in progress
 */
public boolean continueSettling(boolean deferCallbacks) {}
//在父View中的使用
@Override
public void computeScroll() {
    if(mHelper.continueSettling(true)){
        ViewCompat.postInvalidateOnAnimation(this);
    }
}

本人英文不是很好,初步理解就是如果要延迟刷新的话就传入true,返回值如果为True则会重新调用这个方法,直到结束。通常的使用方式就是如上文在父View中使用。至此在父View中我们需要做的就基本结束了。

接下来就是常用方法

      * <p>If this method returns true, a call to {@link #onViewCaptured(android.view.View, int)}
     * will follow if the capture is successful.</p>
     *  决定是否捕获传进来的View
     * @param child Child the user is attempting to capture
     * @param pointerId ID of the pointer attempting the capture
     * @return true if capture should be allowed, false otherwise
     */
    public abstract boolean tryCaptureView(View child, int pointerId);
    /**
     *  决定横向能够拖动的距离
     * @param child Child view being dragged
     * @param left Attempted motion along the X axis
     * @param dx Proposed change in position for left
     * @return The new clamped position for left
     */
    public int clampViewPositionHorizontal(View child, int left, int dx) {
        return 0;
    }
    /**
     *  决定纵向能够拖动的距离
     * @param child Child view being dragged
     * @param top Attempted motion along the Y axis
     * @param dy Proposed change in position for top
     * @return The new clamped position for top
     */
    public int clampViewPositionVertical(View child, int top, int dy) {
        return 0;
    }

三个最常用的方法,在实现拖动的时候基本上都要重写的(第一个是实现),注释已经很明确了,通常在第二,三个方法中直接返回 left,top就可以。

自动复位和边缘拖动

   //手指释放的时候回调
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel)
        {
            //mAutoBackView手指释放时可以自动回去
            if (releasedChild == mAutoBackView)
            {
                mDragger.settleCapturedViewAt(mAutoBackOriginPos.x, mAutoBackOriginPos.y);
                invalidate();
            }
        }

代码来自郭神的博客,当你需要实现自动复位的功能的时候需要重写onViewReleased方法,其中可以对View进行判定(在多个View可以拖动的时候)其中可以实现自动复位的方法有一下三种。

settleCapturedViewAt()是指直接回到初始位置,这个方法的执行过程与松手时的速度有关。如果方法的返回值为true的话,那么continueSettling(boolean)在执行期间会被一直调用,直到方法的返回值为false。

smoothSlideViewTo()是指具有动画效果的回到初始位置。返回值的作用同上。
flingCapturedView()也是一种回到初始位置的方法。不过底层是自己调用的Scroller.fling方法实现的,没有经过forceSettleCapturedViewAt()方法

参考源码我们可以发现,在两种的复位的方法中都使用了forceSettleCapturedViewAt()这个方法来实现具体的复位工作,这个方法的实现是靠Scroller的scroll方法实现的,对于上文中的settle与slide的区别就在于forceSettleCapturedViewAt在被smoothSlideViewTo调用时初始的速度被默认设置为0,看一下具体的实现。
//具有动画效果的复位方法,速度为0
public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) {
mCapturedView = child;
mActivePointerId = INVALID_POINTER;

    boolean continueSliding = forceSettleCapturedViewAt(finalLeft, finalTop, 0, 0);
    if (!continueSliding && mDragState == STATE_IDLE && mCapturedView != null) {
        // If we're in an IDLE state to begin with and aren't moving anywhere, we
        // end up having a non-null capturedView with an IDLE dragState
        mCapturedView = null;
    }

    return continueSliding;
}
//直接恢复到初始位置的复位方法,速度会影响复位的过程
public boolean settleCapturedViewAt(int finalLeft, int finalTop) {
    if (!mReleaseInProgress) {
        throw new IllegalStateException("Cannot settleCapturedViewAt outside of a call to " +
                "Callback#onViewReleased");
    }

    return forceSettleCapturedViewAt(finalLeft, finalTop,
            (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),
            (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId));
}
//两种复位方法的实现。底层的实现是用Scroller
private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) {
    final int startLeft = mCapturedView.getLeft();
    final int startTop = mCapturedView.getTop();
    final int dx = finalLeft - startLeft;
    final int dy = finalTop - startTop;

    if (dx == 0 && dy == 0) {
        // Nothing to do. Send callbacks, be done.
        mScroller.abortAnimation();
        setDragState(STATE_IDLE);
        return false;
    }

    final int duration = computeSettleDuration(mCapturedView, dx, dy, xvel, yvel);
    mScroller.startScroll(startLeft, startTop, dx, dy, duration);

    setDragState(STATE_SETTLING);
    return true;
}
//在forceSettleCapturedViewAt中被调用,用于计算复位的时间
private int computeSettleDuration(View child, int dx, int dy, int xvel, int yvel) {
    xvel = clampMag(xvel, (int) mMinVelocity, (int) mMaxVelocity);
    yvel = clampMag(yvel, (int) mMinVelocity, (int) mMaxVelocity);
    final int absDx = Math.abs(dx);
    final int absDy = Math.abs(dy);
    final int absXVel = Math.abs(xvel);
    final int absYVel = Math.abs(yvel);
    final int addedVel = absXVel + absYVel;
    final int addedDistance = absDx + absDy;

    final float xweight = xvel != 0 ? (float) absXVel / addedVel :
            (float) absDx / addedDistance;
    final float yweight = yvel != 0 ? (float) absYVel / addedVel :
            (float) absDy / addedDistance;

    int xduration = computeAxisDuration(dx, xvel, mCallback.getViewHorizontalDragRange(child));
    int yduration = computeAxisDuration(dy, yvel, mCallback.getViewVerticalDragRange(child));

    return (int) (xduration * xweight + yduration * yweight);
}
//用于计算复位动画的执行时间(单一轴方向上的)
private int computeAxisDuration(int delta, int velocity, int motionRange) {
    if (delta == 0) {
        return 0;
    }
    final int width = mParentView.getWidth();
    final int halfWidth = width / 2;
    final float distanceRatio = Math.min(1f, (float) Math.abs(delta) / width);
    final float distance = halfWidth + halfWidth *
            distanceInfluenceForSnapDuration(distanceRatio);

    int duration;
    velocity = Math.abs(velocity);
    if (velocity > 0) {
        duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
    } else {
        final float range = (float) Math.abs(delta) / motionRange;
        duration = (int) ((range + 1) * BASE_SETTLE_DURATION);
    }
    return Math.min(duration, MAX_SETTLE_DURATION);
}
//计算区间值()
private int clampMag(int value, int absMin, int absMax) {
    final int absValue = Math.abs(value);
    if (absValue < absMin) return 0;
    if (absValue > absMax) return value > 0 ? absMax : -absMax;
    return value;
}
private float clampMag(float value, float absMin, float absMax) {
    final float absValue = Math.abs(value);
    if (absValue < absMin) return 0;
    if (absValue > absMax) return value > 0 ? absMax : -absMax;
    return value;
}
//用于在复位之后释放被捕获的View对象
private float distanceInfluenceForSnapDuration(float f) {
    f -= 0.5f; // center the values about 0.
    f *= 0.3f * Math.PI / 2.0f;
    return (float) Math.sin(f);
}

看了这么多,基本上对于复位就了解的差不多了,一共就有三种选择,可以根据个人喜好和业务需要来选择不同的,其他的一些计算方法,基本不用管,稍微了解就可以,对于前两种方法在使用中的区别明显的在于松手时的速度,一个是有速度变化的复位,一个是平滑的复位。第三种没尝试过。接下来就是边缘拖动所涉及到的方法。

    //设置可以拖动的边缘
    public void setEdgeTrackingEnabled(int edgeFlags) {
        mTrackingEdges = edgeFlags;
    }
    //当父View中一个被设置为可拖动的边界被点击时,并且子view中没有被捕获是调用
    //就是说如果点的位置是可拖动的边缘而且没有在点的位置没有控件被捕获的话会调用此方法。
    public void onEdgeTouched(int edgeFlags, int pointerId) {}

    //该方法当原来可以拖曳的边缘被锁定不可拖曳时回调.如果边缘在初始化开始拖曳前被拒绝拖曳,就会发生前面说的这种情况.
    //但这个方法会在{@link #onEdgeTouched(int, int)}之后才会被回调.这个方法会返回true来锁定该边缘.或者
    //返回false来释放解锁该屏幕.默认的行为是后者(返回false来释放解锁该屏幕)
    //(不是很理解什么时候回被调用,返回值就是值是否锁住当前的边缘,使其变得不可用)
    public boolean onEdgeLock(int edgeFlags) {
        return false;
    }

    //在拖动开始的时候调用,通常用于在此方法中对要施加边缘拖动的View就行确定
    public void onEdgeDragStarted(int edgeFlags, int pointerId) {}

    //在onEdgeDragStarted方法中显示的调用,用来确定要施加边缘拖动的View
    //不受tryCaptureView方法中的返回值限制
    public void captureChildView(View childView, int activePointerId) {
        if (childView.getParent() != mParentView) {
            throw new IllegalArgumentException("captureChildView: parameter must be a descendant " +
                    "of the ViewDragHelper's tracked parent view (" + mParentView + ")");
        }

        mCapturedView = childView;
        mActivePointerId = activePointerId;
        mCallback.onViewCaptured(childView, activePointerId);
        setDragState(STATE_DRAGGING);
    }

上面的注释已经把每个方法的作用说过了,通常我们在使用边缘拖动的时候先设置要实现拖动的边缘,之后在start方法中对要被拖动的View进行显示的确定就行。

在郭神的博客中还对子View是否具有消耗事件的能力进行了一些解析,可以去看一下。

到这基本的使用也就全部解释完了,实际情况中可能别这要复杂得多,比如各种事件的传递与拦截,还有就是与其他的控件间进行适合,都需要大家去尝试。感觉在整体的ViewDragHelper这个类中,最主要的两个方法还是最开始介绍那两个用于传入事件的方法,在其中去有选择性的执行动作和产生各种回调。剩下的一些方Callback中方法在郭神的博客中都有注释,至于ViewDragHelper中的其他方法,可以自行去看源代码,大部分都是set,get方法,判断方法等。其中比较重要的如findTopChildUnder()用于确定拖动View的上下查找顺序(好像不应该这么说,不过作用差不多,底部有调了一个其他的方法去实现的,可以自行查源代码),cancel和abort,用于取消和终止ViewDragHelper。

总结

关于侧滑,从郭神的slidingmenu,到Drawerlayout,再到ViewDragHelper,之前也独立用代码在自定义的布局去根据传入事件的信息来实现View的拖动,但是确实计算量很大而且判定条件都需要自己去写,,动画的实现也需要自己去写,现在有了ViewDragHelper就再也不怕了。弄明白这个类对我们之后实现自定义的ViewGroup有很大的帮助,共勉吧!

最后打个广告。。在找工作。。

参考资料

郭神的两篇博客
http://blog.youkuaiyun.com/lmj623565791/article/details/46858663
http://blog.youkuaiyun.com/lmj623565791/article/details/47396187

超详细的ViewDragHelper源码解析
http://www.it165.net/pro/html/201505/40127.html

这个人写的也特别的好(中午上还能上去的,晚上就不行了)友情参考吧。
http://www.cnphp6.com/archives/87727

ViewDragHelper ViewDragHelper 实现的侧拉滑动效果,可以用来学习 立即下载

相关推荐

《 神奇的 ViewDragHelper,让你轻松定制拥有拖拽能力的 ViewGroup》代码

博客《 神奇的 ViewDragHelper,让你轻松定制拥有拖拽能力的 ViewGroup》的示例代码

Android应用ViewDragHelper详解及部分源码浅析

自定义ViewGroup里通过ViewDragHelper静态工厂方法create()创建实例并实现ViewDragHelper.CallBack抽象类。在自定义ViewGroup的onInterceptTouchEvent()方法里调用并返回ViewDragHelper的shouldInterceptTouchEvent()方法,在onTouchEvent()方法里调用ViewDragHelper()即可完成使用。

工匠若水 1万+

量化交易如何利用涨停板策略收割散户

量化交易通过算法筛选特定特征的股票,在早盘建立底仓后,利用大单拉升制造抢筹假象,吸引散户跟风买入。这种策略利用了散户的认知偏差,如锚定效应和从众心理,导致次日低开闷杀。从技术实现来看,量化策略通过控制买入量、隐藏真实意图等手段,精准执行隔日砸策略。对于短线交易者而言,理解量化资金的运作逻辑和识别危险涨停板的特征至关重要,这包括观察封板时间、盘口挂单、量价关系等多维度数据。在算法主导的市场中,散户需要升级交易工具和策略,从预测走势转向应对走势,才能避免成为量化策略的牺牲品。

weixin_33046983的博客 289

Android ViewDragHelper源码解析

在自定义ViewGroup的过程中,如果涉及到View的拖动滑动,ViewDragHelper的使用应该是少不了的,它提供了一系列用于用户拖动子View的辅助方法和相关的状态记录,像Navigation Drawer的边缘滑动、QQ5.x的侧滑菜单、知乎里的页面滑动返回都可以由它实现,所以有必要完全掌握它的使用。 要想完全掌握ViewDragHelper的使用和原理,最好的办法就是读懂它的源码,所...

weixin_30611509的博客 198

DC-DC 转换器中的压电谐振器:当前状态和限制

在功率转换器应用中,居里温度较低的谐振器的 k 2和 Q M显着降低会导致效率降低,需要仔细的热处理。由于使用 PR 的功率转换器在不同的条件下运行,包括温度范围、电压偏置和功率电平,因此不可避免地会出现非线性效应,必须妥善解决这一问题,以免影响转换器的性能。等效电路模型(Butterworth Van-Dyke 或 BVD 模型)将压电谐振器在其机械谐振附近的电响应转换为一个简单电路,该电路由与由电极形成的输入电容 C 0并联的串联 RLC 动分支组成,见图图 1 还显示了阻抗与频率的关系。

2301_79716471的博客 1298

VCU128开发板上手记:搞定100G以太网IP核与QSFP光模块的那些坑

本文详细介绍了在VCU128开发板上实现100G以太网IP核与QSFP光模块调试的实战经验。从硬件准备、IP核配置到QSFP模块控制信号处理,文章揭示了数据手册中未提及的关键细节,并提供了优化参数和压力测试方案,帮助开发者快速解决UltraScale+平台下的高速以太网部署难题。

weixin_30740295的博客 521

Android事件分发机制的神秘面纱

今天看了鸿神他的博文之后有点感触,对就像他们所说事件分发这东西不是一二句话就能解释明白的,真正要了解他们的内部机制怎样运行还是需要去研究源码,因为那里基本可以找到答案首先看下效果然后看下log日志根据你的拖拽看他是向上还是向左移动这个方法比较重要创建实例需要3个参数,第一个就是当前的ViewGroup,第二个sensitivity,主要用于设置touchSlop: 源码可以看到 public st

郑敏 1006

1篇2章1节:在 Mac 上安装 Python,从环境检查到工具配置的完整指南

Python 是当今最流行的高级编程语言之一,广泛应用于数据分析、人工智能、自动化脚本和 Web 开发。虽然 macOS 曾自带 Python,但从 macOS 12.3 开始,系统不再默认提供可直接使用的版本,因此需要手动安装。本文将详细讲解如何在 Mac 上安装最新版本的 Python,如何验证安装是否成功,以及如何配置 IDLE 和 Python Launcher 等工具,为日常开发和学习打下坚实基础。即便你是完全的新手,也能按步骤完成环境搭建。

MD Code 849

2018年首篇,带大家一起学习视图拖拽功能的源码

今天的快讯我们对2017年的重大事件进行一下回顾吧。 乐视事件 回溯乐视的2017,“眼看他起朱楼,眼看他宴宾客,眼看他楼塌了”。乐视历经了来自融创中国百亿融资、高层相继离职、裁员风波、资金链危机、业务亏损,以及旗下的手机业务停摆、供应商讨债等一系列危机,乐视生态几近崩溃。贾跃亭则赴美专注法拉第未来,称会将全部精力放在造车项目上。12月25日,北京证监局发布通告,责令贾跃亭于2017年

1358

FM20S用户手册-PL端案例开发手册

为便于演示,本次操作直接将led_flash案例中的 "led_flash_fm20s\constraints\constrs_1Ved_flash_fm20s.fdc"文件全部代码拷贝至编辑 界面,并点击保存按钮。引脚约束请查看案例工程"led_flash\project\led_flash_fm20s\constraints\constrs_1\"目 录下的led_flash_fm20sfdc。(4)弹出如下界面,在界面配置Select device forthe project"内容,如下图。

创龙,嵌入式一体化解决方案商 401

2025美赛E题为农业留出空间(附代码+全保姆教程)Making Room for Agriculture

有机农业的核心在于减少化学投入,促进自然控制和可持续性。变量定义CCC: 作物种群III: 害虫种群PPP: 天然捕食者种群(蝙蝠、鸟类等)BBB: 生物多样性水平(以种类数量表示)SSS: 土壤健康指数(影响植物繁殖与作物生长)EEE: 农业生态系统的整体稳定性。

博客 1495

学习记录:自定义View(仿汽车之家下拉选择页面 继承自FrameLayout)

    目前现在的状态还是对于常用的类所包装的函数不是太了解的状态。    一个重要的辅助类: ViewDragHelper;    新建ViewDragHelper对象时,需要传入callback回调函数对象: private ViewDragHelper.Callback mCallBack = new ViewDragHelper.Callback(){}回调函数中需要复写的几个重要方法:@...

dreaminger156的博客 835

C# 与蓝牙 BLE 设备通信:基于 Windows.Devices.Bluetooth 实现手环/传感器数据读取

本文介绍了如何利用C#的Windows.Devices.Bluetooth命名空间实现与蓝牙BLE设备的通信。首先概述了BLE技术特性及其在物联网中的应用场景,包括智能穿戴设备和传感器。随后讲解了BLE的GATT协议架构,解析了服务(Service)和特性(Characteristic)的概念。文章重点展示了通过C#实现设备扫描、连接、数据读取的完整代码示例,并详细说明了如何使用通知(Notifications)功能实现实时数据更新。最后提供了订阅心率测量特性变化的实现代码,为开发者提供了完整的BLE设备通

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1323

ViewDragHelper 的使用及源码分析

ViewDragHelper 是一个关于拖动view的辅助类,一般view的位移有几种方法,一般都是监听view的 onTouchEvent() 事件,我们需要作出一系列判断,如果再加上边界值的判断,比如滑到父控件左边时提示用户到了边缘,滑到了右边时要结束当前Activity,这种情况我们需要进一步判断,添加回调,这样写下来,一方面是麻烦,另外一方面是代码繁琐,不利于扩展并不利于复用,为了解决这些...

Deaht_Huimie的博客 414

YOLOV5 自动刷图脚本实战(十五)之如何找到正确的门

DXF是一个2D游戏,我们所看到的人物移动,其实是后面的背景在移动,我们所看到的画面,不过是一个完整背景中的一个镜头视角而已想要正确找到门的坐标,我们需要对不同的地图中的每个房间做一些配置信息。

qq_38892949的博客 2812

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

ViewDragHelper的源码分析及概述学习

一、概述 使用到ViewDragHelper是自己在做仿微信的侧滑删除操作时用到的,需要对Recycleview内的Item的滑动事件做处理,并将隐藏在屏幕右侧的view滑出来做出删除操作。自己的demo删除了,这里就借用一下ITluochen大神的demo,主要是能为自己以后用到ViewDragHelper提供方便与指引,ITluochen大神的demo讲解的其实非常详细了,大家也

ap____lLix1的博客 619

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

ViewDragHelper,入门级源码分析

ViewDragHelper,入门级源码分析 本篇文章将ViewDragHelper,分为这么几个模块,逐步了解ViewDragHelp的使用,希望能够让一些不懂的开发者了解怎么样使用,让一些懂的开发者能够进一步的了解为什么需要这样做; -ViewDragHelper的简介和来源; -ViewDragHelper的基本使用; -ViewDragHelper源码浅谈 ViewDragHel

Dinasour~~~ 400

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Viewdraghelper解析

Viewdraghelper解析 2013年谷歌i/o大会上介绍了两个新的layout: SlidingPaneLayout和DrawerLayout,现在这俩个类被广泛的运用, 其实研究他们的源码你会发现这两个类都运用了ViewDragHelper来处理拖动。ViewDragHelper是framework中非常有用的一个工具。 ViewDragHelper解决了

wxx614817的专栏 691

Android ViewDragHelper使用及原理

Android ViewDragHelper使用及原理1.初始化2.拦截事件处理3.拖动事件处理(1)拖动(2)释放(3)滚动 ViewDragHelper类,是用来处理View边界拖动相关的类,比如我们这里要用的例子—侧滑拖动关闭页面(类似微信),该功能很明显是要处理在View上的触摸事件,记录触摸点、计算距离、滚动动画、状态回调等,如果我们自己手动实现自然会很麻烦还可能出错,而这个类会帮助我们...

依生依世 902

Android V4包下DrawerLayout的学习及回顾

好久没看DrawerLayout.我记得去年刚开始学习Android的时候,Drawerlayout只是一个简单的带把手的一个抽屉,市面上很少用,貌似那时候的QQ管家就用了这个控件.今天突然翻出来,发现Google已经废弃掉了抽屉的把手了,个人也是不太喜欢把手的,因为遮挡了视图,[那时候手机屏幕还是很小的时候].刚才玩弄了一下,给大家分享一下. 我的开发环境是Android Studio 1.2

Tanck的专栏 1069

Android应用ViewDragHelper详解及部分源码浅析,Android面试真题精选

mCurTop = top; requestLayout(); } @Override public int getViewVerticalDragRange(View child) { if (mDrawerView == null) return 0; return (mDrawerView == child) ? mDrawerView.getHeight() : 0; } @Override public void onViewDragStateChanged(int state) { super.

m0_65145685的博客 232

Android应用ViewDragHelper详解及部分源码浅析,kotlin版权

【工匠若水 http://blog.youkuaiyun.com/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我】 3 ViewDragHelper局部源码浅析 ========================== 上面的例子中我们可以知道,使用ViewDragHelper的第一步就是通过他提供的静态工厂方法create获取实例,因为ViewDragHelper的构造方法是私有的。既然这样那我们先看下这些静态工厂方法,如下: public class ViewDragHelper { public

m0_64383081的博客 659
上一篇: ViewPropertyAnimator源码分析
下一篇: 自定义View--你要掌握的基本知识
hbl_for_android
博客等级 码龄11年 30粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值