概述

新版的音悦台 APP 播放页面交互非常有意思,可以把播放器往下拖动,然后在底部悬浮一个小框,还可以左右拖动,然后回弹的时候也会有相应的效果,这种交互效果在头条视频和一些专注于视频的app也是很常见的。 
前几天看网友有仿这个 效果,觉得不错,现在分享出来,代码可以再优化,这里的播放器使用的是B站的ijkplayer,先上两张动图。 
 
当图片到达底部后,左右拖动 

实现的思路

首先,要是拖动视图缩小的效果,我们肯定需要自定义一个View,而根据我们项目的场景我们这里需要两个View,一个是拖动的View,另一个是浮动上下的View(可以缩小的View),为了实现拖动,我们知道必定会用到ViewDragHelper这个类,这个类专门为了拖动而设计的。 
然后,对于拖动到底部的View,我们需要实现左右拖动的效果,这个其实也是比较容易实现的,我们通过ViewDragHelper的onViewPositionChanged方法来判断当前视图的状况,就可以做View进行缩放和渐变了。

代码分析

首先我们会自定义一个容器,容器的init方法会初始化两个View:mFlexView (到底拖动的View)和mFollowView (跟随触摸缩放的View)

 private void init(Context context, AttributeSet attrs) {final float density = getResources().getDisplayMetrics().density;final float minVel = MIN_FLING_VELOCITY * density;ViewGroupCompat.setMotionEventSplittingEnabled(this, false);FlexCallback flexCallback = new FlexCallback();mDragHelper = ViewDragHelper.create(this, 1.0f, flexCallback);// 最小拖动速度mDragHelper.setMinVelocity(minVel);post(new Runnable() {@Overridepublic void run() {// 需要添加的两个子View,其中mFlexView作为拖动的响应View,mLinkView作为跟随ViewmFlexView = getChildAt(0);mFollowView = getChildAt(1);mDragHeight = getMeasuredHeight() - mFlexView.getMeasuredHeight();mFlexWidth = mFlexView.getMeasuredWidth();mFlexHeight = mFlexView.getMeasuredHeight();}});}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

ViewDragHelper 的回调需要做的事情比较多,在 mFlexView 拖动的时候需要同时设置 mFlexView 和 mFollowView 的相应变化效果,在 mFlexView 释放的时候需要处理关闭或收起等效果。所以这里我们需要对ViewDragHelper个各种回调事件进行监听。这也是本功能最核心的:

 private class FlexCallback extends ViewDragHelper.Callback {@Overridepublic boolean tryCaptureView(View child, int pointerId) {// mFlexView来响应触摸事件return mFlexView == child;}@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {return Math.max(Math.min(mDragWidth, left), -mDragWidth);}@Overridepublic int getViewHorizontalDragRange(View child) {return mDragWidth * 2;}@Overridepublic int clampViewPositionVertical(View child, int top, int dy) {if (!mVerticalDragEnable) {// 不允许垂直拖动的时候是mFlexView在底部水平拖动一定距离时设置的,返回mDragHeight就不能再垂直做拖动了return mDragHeight;}return Math.max(Math.min(mDragHeight, top), 0);}@Overridepublic int getViewVerticalDragRange(View child) {return mDragHeight;}@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {if (mHorizontalDragEnable) {// 如果水平拖动有效,首先根据拖动的速度决定关闭页面,方向根据速度正负决定if (xvel > 1500) {mDragHelper.settleCapturedViewAt(mDragWidth, mDragHeight);mIsClosing = true;} else if (xvel < -1500) {mDragHelper.settleCapturedViewAt(-mDragWidth, mDragHeight);mIsClosing = true;} else {// 速度没到关闭页面的要求,根据透明度来决定关闭页面,方向根据releasedChild.getLeft()正负决定float alpha = releasedChild.getAlpha();if (releasedChild.getLeft() < 0 && alpha <= 0.4f) {mDragHelper.settleCapturedViewAt(-mDragWidth, mDragHeight);mIsClosing = true;} else if (releasedChild.getLeft() > 0 && alpha <= 0.4f) {mDragHelper.settleCapturedViewAt(mDragWidth, mDragHeight);mIsClosing = true;} else {mDragHelper.settleCapturedViewAt(0, mDragHeight);}}} else {// 根据垂直方向的速度正负决定布局的展示方式if (yvel > 1500) {mDragHelper.settleCapturedViewAt(0, mDragHeight);} else if (yvel < -1500) {mDragHelper.settleCapturedViewAt(0, 0);} else {// 根据releasedChild.getTop()决定布局的展示方式if (releasedChild.getTop() <= mDragHeight / 2) {mDragHelper.settleCapturedViewAt(0, 0);} else {mDragHelper.settleCapturedViewAt(0, mDragHeight);}}}invalidate();}@Overridepublic void onViewPositionChanged(final View changedView, int left, int top, int dx, int dy) {float fraction = top * 1.0f / mDragHeight;// mFlexView缩放的比率mFlexScaleRatio = 1 - 0.5f * fraction;mFlexScaleOffset = changedView.getWidth() / 20;// 设置缩放基点changedView.setPivotX(changedView.getWidth() - mFlexScaleOffset);changedView.setPivotY(changedView.getHeight() - mFlexScaleOffset);// 设置比例changedView.setScaleX(mFlexScaleRatio);changedView.setScaleY(mFlexScaleRatio);// mFollowView透明度的比率float alphaRatio = 1 - fraction;// 设置透明度mFollowView.setAlpha(alphaRatio);// 根据垂直方向的dy设置top,产生跟随mFlexView的效果mFollowView.setTop(mFollowView.getTop() + dy);// 到底部的时候,changedView的top刚好等于mDragHeight,以此作为水平拖动的基准mHorizontalDragEnable = top == mDragHeight;if (mHorizontalDragEnable) {// 如果水平拖动允许的话,由于设置缩放不会影响mFlexView的宽高(比如getWidth),所以水平拖动距离为mFlexView宽度一半mDragWidth = (int) (changedView.getMeasuredWidth() * 0.5f);// 设置mFlexView的透明度,这里向左右水平拖动透明度都随之变化changedView.setAlpha(1 - Math.abs(left) * 1.0f / mDragWidth);// 水平拖动一定距离的话,垂直拖动将被禁止mVerticalDragEnable = left < 0 && left >= -mDragWidth * 0.05;} else {// 不是水平拖动的处理changedView.setAlpha(1);mDragWidth = 0;mVerticalDragEnable = true;}if (mFlexLayoutPosition == null) {// 创建子元素位置缓存mFlexLayoutPosition = new ChildLayoutPosition();mFollowLayoutPosition = new ChildLayoutPosition();}// 记录子元素的位置mFlexLayoutPosition.setPosition(mFlexView.getLeft(), mFlexView.getRight(), mFlexView.getTop(), mFlexView.getBottom());mFollowLayoutPosition.setPosition(mFollowView.getLeft(), mFollowView.getRight(), mFollowView.getTop(), mFollowView.getBottom());//            Log.e("FlexCallback", "225行-onViewPositionChanged(): 【" + mFlexView.getLeft() + ":" + mFlexView.getRight() + ":" + mFlexView.getTop() + ":" + mFlexView//                    .getBottom() + "】 【" + mFollowView.getLeft() + ":" + mFollowView.getRight() + ":" + mFollowView.getTop() + ":" + mFollowView.getBottom() + "】");}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134

接下来是处理测量和定位,我们实现的排列效果类似 LinearLayout 垂直排列的效果,这里需要对 measureChildWithMargins 的 heightUse 重新设置;onLayout 的时候在位置缓存不为空的时候直接定位是因为 ViewDragHelper 在处理触摸事件子元素在做一些平移之类的,若是有元素更新了 UI 会导致重新 Layout,因此在 FlexCallback 的 onViewPositionChanged 方法记录位置,然后在回弹的时候需要通过Layout 恢复之前的视图。

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int desireHeight = 0;int desireWidth = 0;int tmpHeight = 0;if (getChildCount() != 2) {throw new IllegalArgumentException("只允许容器添加两个子View!");}if (getChildCount() > 0) {for (int i = 0; i < getChildCount(); i++) {final View child = getChildAt(i);// 测量子元素并考虑外边距// 参数heightUse:父容器竖直已经被占用的空间,比如被父容器的其他子 view 所占用的空间;这里我们需要的是子View垂直排列,所以需要设置这个值measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, tmpHeight);// 获取子元素的布局参数final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();// 计算子元素宽度,取子控件最大宽度desireWidth = Math.max(desireWidth, child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);// 计算子元素高度tmpHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;desireHeight += tmpHeight;}// 考虑父容器内边距desireWidth += getPaddingLeft() + getPaddingRight();desireHeight += getPaddingTop() + getPaddingBottom();// 尝试比较建议最小值和期望值的大小并取大值desireWidth = Math.max(desireWidth, getSuggestedMinimumWidth());desireHeight = Math.max(desireHeight, getSuggestedMinimumHeight());}// 设置最终测量值setMeasuredDimension(resolveSize(desireWidth, widthMeasureSpec), resolveSize(desireHeight, heightMeasureSpec));}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {if (mFlexLayoutPosition != null) {// 因为在用到ViewDragHelper处理布局交互的时候,若是有子View的UI更新导致重新Layout的话,需要我们自己处理ViewDragHelper拖动时子View的位置,否则会导致位置错误// Log.e("YytLayout1", "292行-onLayout(): " + "自己处理布局位置");mFlexView.layout(mFlexLayoutPosition.getLeft(), mFlexLayoutPosition.getTop(), mFlexLayoutPosition.getRight(), mFlexLayoutPosition.getBottom());mFollowView.layout(mFollowLayoutPosition.getLeft(), mFollowLayoutPosition.getTop(), mFollowLayoutPosition.getRight(), mFollowLayoutPosition.getBottom());return;}final int paddingLeft = getPaddingLeft();final int paddingTop = getPaddingTop();int multiHeight = 0;int count = getChildCount();if (count != 2) {throw new IllegalArgumentException("此容器的子元素个数必须为2!");}for (int i = 0; i < count; i++) {// 遍历子元素并对其进行定位布局final View child = getChildAt(i);MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int left = paddingLeft + lp.leftMargin;int right = child.getMeasuredWidth() + left;int top = (i == 0 ? paddingTop : 0) + lp.topMargin + multiHeight;int bottom = child.getMeasuredHeight() + top;child.layout(left, top, right, bottom);multiHeight += (child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

触摸事件的处理,由于缩放不会影响 mFlexView 真实宽高,ViewDragHelper 仍然会阻断 mFlexView 的真实宽高的区域,所以这里判断手指是否落在 mFlexView 视觉上的范围内,在才去调 ViewDragHelper 的 shouldInterceptTouchEvent 方法。

 @Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// Log.e("YytLayout", mFlexView.getLeft() + ";" + mFlexView.getTop() + " --- " + ev.getX() + ":" + ev.getY());// 由于缩放不会影响mFlexView真实宽高,这里手动计算视觉上的范围float left = mFlexView.getLeft() + mFlexWidth * (1 - mFlexScaleRatio) - mFlexScaleOffset * (1 - mFlexScaleRatio);float top = mFlexView.getTop() + mFlexHeight * (1 - mFlexScaleRatio) - mFlexScaleOffset * (1 - mFlexScaleRatio);// 这里所做的是判断手指是否落在mFlexView视觉上的范围内mInFlexViewTouchRange = ev.getX() >= left && ev.getY() >= top;if (mInFlexViewTouchRange) {return mDragHelper.shouldInterceptTouchEvent(ev);} else {return super.onInterceptTouchEvent(ev);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (mInFlexViewTouchRange) {// 这里还要做判断是因为,即使我不阻断事件,但是此Layout的子View不消费的话,事件还是给回此LayoutmDragHelper.processTouchEvent(event);return true;} else {// 不在mFlexView触摸范围内,并且子View没有消费,返回false,把事件传递回去return false;}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

同时我们需要对滚动事件进行监听,我们需要在此关闭的整个平移执行事件。

  @Overridepublic void computeScroll() {if (mDragHelper.continueSettling(true)) {invalidate();} else if (mIsClosing && mOnLayoutStateListener != null) {// 正在关闭的情况下,并且拖动结束后,告知将要关闭页面mOnLayoutStateListener.onClose();mIsClosing = false;}}/*** 监听布局是否水平拖动关闭了*/public interface OnLayoutStateListener {void onClose();}public void setOnLayoutStateListener(OnLayoutStateListener onLayoutStateListener) {mOnLayoutStateListener = onLayoutStateListener;}/*** 展开布局*/public void expand() {mDragHelper.smoothSlideViewTo(mFlexView, 0, 0);invalidate();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

而在实际的应用中要实现回弹后详情页面的效果,我们需要自己实现一个组合View,这个大家可以自己看源码音悦台源码

附:ViewDragHelper及移动事件处理

android 仿音悦台页面交互效果相关推荐

  1. Android编写界面交互代码,android仿音悦台页面交互效果实例代码

    概述 新版的音悦台 APP 播放页面交互非常有意思,可以把播放器往下拖动,然后在底部悬浮一个小框,还可以左右拖动,然后回弹的时候也会有相应的效果,这种交互效果在头条视频和一些专注于视频的app也是很常 ...

  2. android仿微信的activity平滑水平切换动画,Android实现简单底部导航栏 Android仿微信滑动切换效果...

    Android实现简单底部导航栏 Android仿微信滑动切换效果 发布时间:2020-10-09 19:48:00 来源:脚本之家 阅读:96 作者:丶白泽 Android仿微信滑动切换最终实现效果 ...

  3. android仿ppt,android 仿ppt进入动画效果合集

    EnterAnimation android 仿ppt进入动画效果合集, 百叶窗效果,擦除效果,盒状效果,阶梯效果,菱形效果,轮子效果,劈裂效果,棋盘效果, 切入效果,扇形展开效果,十字扩展效果,随机 ...

  4. android 仿ppt进入动画效果合集

    EnterAnimation android 仿ppt进入动画效果合集, 百叶窗效果,擦除效果,盒状效果,阶梯效果,菱形效果,轮子效果,劈裂效果,棋盘效果, 切入效果,扇形展开效果,十字扩展效果,随机 ...

  5. android 折叠式布局,Android卡片式折叠交互效果

    原标题:Android卡片式折叠交互效果 近日有报道称:在互联网共享单车最早起步的上海,目前有150万辆共享单车.迅猛的增速之下,上海市交通委紧急叫停,成为继杭州.广州等城市之后,国内又一个暂停新增投 ...

  6. 基于android的高仿抖音,Android仿抖音列表效果

    本文实例为大家分享了Android仿抖音列表效果的具体代码,供大家参考,具体内容如下 当下抖音非常火热,是不是也很心动做一个类似的app吗? 那我们就用RecyclerView实现这个功能吧,关于内存 ...

  7. Android仿微信头像放大效果

    android仿微信头像放大效果,使用Dialog+Gallery 实现 1.  dialog显示时的动画style,动画可以自己根据喜好自己设置,此处动画xml省略 <style name=& ...

  8. android仿抖音礼物列表实现,Android仿抖音列表效果

    本文实例为大家分享了Android仿抖音列表效果的具体代码,供大家参考,具体内容如下 当下抖音非常火热,是不是也很心动做一个类似的app吗? 那我们就用RecyclerView实现这个功能吧,关于内存 ...

  9. android仿抖音关注列表,Android仿抖音列表效果

    本文实例为大家分享了Android仿抖音列表效果的具体代码,供大家参考,具体内容如下 当下抖音非常火热,是不是也很心动做一个类似的app吗? 那我们就用RecyclerView实现这个功能吧,关于内存 ...

最新文章

  1. 大数据架构如何挑选机器.
  2. Spring与Struts框架整合
  3. dev_open linux,linux 伪终端设备 /dev/ptmx
  4. VC MFC 发送模仿键盘消息
  5. 2022最新教程,半小时速通Git和Github的基本操作。
  6. 《构建之法》CH5~6读书笔记 PB16110698 第九周(~5.15)
  7. 服务器硬件维护指南和解决方案
  8. tp框架获取服务器信息,tp5获取服务器地址
  9. 白岩松人生哲学-听后感
  10. linux系统外接硬盘_电脑主硬盘linux系统,外接硬盘win7系统.如何启动外接硬盘的win7系统?...
  11. Hive 的 distribute by
  12. handle java
  13. 哈工大 编译原理 复习笔记
  14. 《软件测试---你必须掌握的100个问题》
  15. 消息队列:比较Beanstalkd,IronMQ和Amazon SQS
  16. 你可能用错了 kafka 的重试机制
  17. RFID物流配送智慧管理解决方案
  18. VB.net / 工业相机SDK / 获取Halcon图像
  19. 网站备案接入变更 - 记录从阿里云转到腾讯云的过程
  20. Visual Studio 2019许可证授权

热门文章

  1. Windows下安装NTP服务器——搭建时间同步服务器
  2. 云南大学c语言实验报告3,云南大学软件学院C语言所有实验代码.doc
  3. 天然气地下管道智慧应急指挥系统平台,24小时为你保驾护航
  4. html杜邦分析图,如何把网页上的杜邦分析图复制到Word里?
  5. PTrade交易程序代码——从零到实盘19
  6. eclipse中,run as 没有出现java application
  7. 【网络流24题】圆桌聚餐
  8. ldap认证 java_Java实现LDAP认证(上) | 学步园
  9. 基于R的金融收益的分析和预测
  10. 电脑上使用计算机命令行,我的电脑运行命令_我的电脑什么运行命令