QQ的未读消息,算是一个比较好玩的效果,趁着最近时间比较多,参考了网上的一些资料之后,本次实现一个仿照QQ未读消息的拖拽小红点:

首先我们从最基本的原理开始分析,看一张图:

这个图该怎么绘制呢?实际上我们这里是先绘制两个圆,然后将两个圆的切点通过贝塞尔曲线连接起来就达到这个效果了。至于贝塞尔曲线的概念,这里就不多做解释了,百度一下就知道了。

切点怎么算呢,这里我们稍微复习一些初中的数学知识。看了这个图之后,求出四个切点应该是轻而易举了。

现在思路已经很清晰了,按照我们的思路,开撸。

首先是我们计算切点以及各坐标点的工具类

  1. public class GeometryUtils {
  2. /**
  3. * As meaning of method name.
  4. * 获得两点之间的距离
  5. * @param p0
  6. * @param p1
  7. * @return
  8. */
  9. public static float getDistanceBetween2Points(PointF p0, PointF p1) {
  10. float distance = (float) Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2));
  11. return distance;
  12. }
  13. /**
  14. * Get middle point between p1 and p2.
  15. * 获得两点连线的中点
  16. * @param p1
  17. * @param p2
  18. * @return
  19. */
  20. public static PointF getMiddlePoint(PointF p1, PointF p2) {
  21. return new PointF((p1.x + p2.x) / 2.0f, (p1.y + p2.y) / 2.0f);
  22. }
  23. /**
  24. * Get point between p1 and p2 by percent.
  25. * 根据百分比获取两点之间的某个点坐标
  26. * @param p1
  27. * @param p2
  28. * @param percent
  29. * @return
  30. */
  31. public static PointF getPointByPercent(PointF p1, PointF p2, float percent) {
  32. return new PointF(evaluateValue(percent, p1.x , p2.x), evaluateValue(percent, p1.y , p2.y));
  33. }
  34. /**
  35. * 根据分度值,计算从start到end中,fraction位置的值。fraction范围为0 -> 1
  36. * @param fraction
  37. * @param start
  38. * @param end
  39. * @return
  40. */
  41. public static float evaluateValue(float fraction, Number start, Number end){
  42. return start.floatValue() + (end.floatValue() - start.floatValue()) * fraction;
  43. }
  44. /**
  45. * Get the point of intersection between circle and line.
  46. * 获取 通过指定圆心,斜率为lineK的直线与圆的交点。
  47. *
  48. * @param pMiddle The circle center point.
  49. * @param radius The circle radius.
  50. * @param lineK The slope of line which cross the pMiddle.
  51. * @return
  52. */
  53. public static PointF[] getIntersectionPoints(PointF pMiddle, float radius, Double lineK) {
  54. PointF[] points = new PointF[2];
  55. float radian, xOffset = 0, yOffset = 0;
  56. if(lineK != null){
  57. radian= (float) Math.atan(lineK);
  58. xOffset = (float) (Math.sin(radian) * radius);
  59. yOffset = (float) (Math.cos(radian) * radius);
  60. }else {
  61. xOffset = radius;
  62. yOffset = 0;
  63. }
  64. points[0] = new PointF(pMiddle.x + xOffset, pMiddle.y - yOffset);
  65. points[1] = new PointF(pMiddle.x - xOffset, pMiddle.y + yOffset);
  66. return points;
  67. }
  68. }

然后下面看下我们的核心绘制代码,代码注释比较全,此处就不多做解释了。

  1. /**
  2. * 绘制贝塞尔曲线部分以及固定圆
  3. *
  4. * @param canvas
  5. */
  6. private void drawGooPath(Canvas canvas) {
  7. Path path = new Path();
  8. //1. 根据当前两圆圆心的距离计算出固定圆的半径
  9. float distance = (float) GeometryUtils.getDistanceBetween2Points(mDragCenter, mStickCenter);
  10. stickCircleTempRadius = getCurrentRadius(distance);
  11. //2. 计算出经过两圆圆心连线的垂线的dragLineK(对边比临边)。求出四个交点坐标
  12. float xDiff = mStickCenter.x - mDragCenter.x;
  13. Double dragLineK = null;
  14. if (xDiff != 0) {
  15. dragLineK = (double) ((mStickCenter.y - mDragCenter.y) / xDiff);
  16. }
  17. //分别获得经过两圆圆心连线的垂线与圆的交点(两条垂线平行,所以dragLineK相等)。
  18. PointF[] dragPoints = GeometryUtils.getIntersectionPoints(mDragCenter, dragCircleRadius, dragLineK);
  19. PointF[] stickPoints = GeometryUtils.getIntersectionPoints(mStickCenter, stickCircleTempRadius, dragLineK);
  20. //3. 以两圆连线的0.618处作为 贝塞尔曲线 的控制点。(选一个中间点附近的控制点)
  21. PointF pointByPercent = GeometryUtils.getPointByPercent(mDragCenter, mStickCenter, 0.618f);
  22. // 绘制两圆连接闭合
  23. path.moveTo((float) stickPoints[0].x, (float) stickPoints[0].y);
  24. path.quadTo((float) pointByPercent.x, (float) pointByPercent.y,
  25. (float) dragPoints[0].x, (float) dragPoints[0].y);
  26. path.lineTo((float) dragPoints[1].x, (float) dragPoints[1].y);
  27. path.quadTo((float) pointByPercent.x, (float) pointByPercent.y,
  28. (float) stickPoints[1].x, (float) stickPoints[1].y);
  29. canvas.drawPath(path, mPaintRed);
  30. // 画固定圆
  31. canvas.drawCircle(mStickCenter.x, mStickCenter.y, stickCircleTempRadius, mPaintRed);
  32. }

此时我们已经实现了绘制的核心代码,然后我们加上touch事件的监听,达到动态的更新dragPoint的中心点位置以及stickPoint半径的效果。当手抬起的时候,添加一个属性动画,达到回弹的效果。

  1. @Override
  2. public boolean onTouchEvent(MotionEvent event) {
  3. switch (MotionEventCompat.getActionMasked(event)) {
  4. case MotionEvent.ACTION_DOWN: {
  5. isOutOfRange = false;
  6. updateDragPointCenter(event.getRawX(), event.getRawY());
  7. break;
  8. }
  9. case MotionEvent.ACTION_MOVE: {
  10. //如果两圆间距大于最大距离mMaxDistance,执行拖拽结束动画
  11. PointF p0 = new PointF(mDragCenter.x, mDragCenter.y);
  12. PointF p1 = new PointF(mStickCenter.x, mStickCenter.y);
  13. if (GeometryUtils.getDistanceBetween2Points(p0, p1) > mMaxDistance) {
  14. isOutOfRange = true;
  15. updateDragPointCenter(event.getRawX(), event.getRawY());
  16. return false;
  17. }
  18. updateDragPointCenter(event.getRawX(), event.getRawY());
  19. break;
  20. }
  21. case MotionEvent.ACTION_UP: {
  22. handleActionUp();
  23. break;
  24. }
  25. default: {
  26. isOutOfRange = false;
  27. break;
  28. }
  29. }
  30. return true;
  31. }
  32. /**
  33. * 手势抬起动作
  34. */
  35. private void handleActionUp() {
  36. if (isOutOfRange) {
  37. // 当拖动dragPoint范围已经超出mMaxDistance,然后又将dragPoint拖回mResetDistance范围内时
  38. if (GeometryUtils.getDistanceBetween2Points(mDragCenter, mStickCenter) < mResetDistance) {
  39. //reset
  40. return;
  41. }
  42. // dispappear
  43. } else {
  44. //手指抬起时,弹回动画
  45. mAnim = ValueAnimator.ofFloat(1.0f);
  46. mAnim.setInterpolator(new OvershootInterpolator(5.0f));
  47. final PointF startPoint = new PointF(mDragCenter.x, mDragCenter.y);
  48. final PointF endPoint = new PointF(mStickCenter.x, mStickCenter.y);
  49. mAnim.addUpdateListener(new AnimatorUpdateListener() {
  50. @Override
  51. public void onAnimationUpdate(ValueAnimator animation) {
  52. float fraction = animation.getAnimatedFraction();
  53. PointF pointByPercent = GeometryUtils.getPointByPercent(startPoint, endPoint, fraction);
  54. updateDragPointCenter((float) pointByPercent.x, (float) pointByPercent.y);
  55. }
  56. });
  57. mAnim.addListener(new AnimatorListenerAdapter() {
  58. @Override
  59. public void onAnimationEnd(Animator animation) {
  60. //reset
  61. }
  62. });
  63. if (GeometryUtils.getDistanceBetween2Points(startPoint, endPoint) < 10) {
  64. mAnim.setDuration(100);
  65. } else {
  66. mAnim.setDuration(300);
  67. }
  68. mAnim.start();
  69. }
  70. }

此时我们拖拽的核心代码基本都已经完成,实际效果如下:

现在小红点的绘制基本告一段落,我们不得不去思考真正的难点。那就是如何将我们前面的这个GooView应用到实际呢?看实际效果我们的小红点是放在listView里面的,如果是这样的话,就代表我们的GooView的拖拽范围是肯定无法超过父控件item的区域的。

那么我们要如何实现小红点可以随便的在整个屏幕拖拽呢?我们这里稍微整理一下思路。

1.先在listView的item布局中先放入一个小红点。

2.当我们touch到这个小红点的时候,隐藏这个小红点,然后根据我们布局中小红点的位置初始化一个GooView并且添加到WindowManager中吗,达到GooView可以全屏拖动的效果。

3.在添加GooView到WindowManager中的时候,记录初始小红点stickPoint的位置,然后根据stickPoint和dragPointde位置是否超出我们的消失界限来判断接下来的逻辑。

4.根据GooView的最终状态,显示回弹或者消失动画。

思路有了,那么就上代码,根据第一步,我们完成listView的item布局。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="80dp"
  5. android:minHeight="80dp">
  6. <ImageView
  7. android:id="@+id/iv_head"
  8. android:layout_width="50dp"
  9. android:layout_height="50dp"
  10. android:layout_centerVertical="true"
  11. android:layout_marginLeft="20dp"
  12. android:src="@mipmap/head"/>
  13. <TextView
  14. android:id="@+id/tv_content"
  15. android:layout_width="wrap_content"
  16. android:layout_height="50dp"
  17. android:layout_centerVertical="true"
  18. android:gravity="center"
  19. android:layout_marginLeft="20dp"
  20. android:layout_toRightOf="@+id/iv_head"
  21. android:text="content - "
  22. android:textSize="25sp"/>
  23. <LinearLayout
  24. android:id="@+id/ll_point"
  25. android:layout_width="80dp"
  26. android:layout_height="80dp"
  27. android:layout_alignParentEnd="true"
  28. android:layout_alignParentRight="true"
  29. android:layout_alignParentTop="true"
  30. android:gravity="center">
  31. <TextView
  32. android:id="@+id/point"
  33. android:layout_width="wrap_content"
  34. android:layout_height="18dp"
  35. android:background="@drawable/red_bg"
  36. android:gravity="center"
  37. android:singleLine="true"
  38. android:textColor="@android:color/white"
  39. android:textSize="12sp"/>
  40. </LinearLayout>
  41. </RelativeLayout>

效果如下,要注意的是,对比QQ的真实体验,小红点周边范围点击的时候,都是可以直接拖拽小红点的。考虑到红点的点击范围比较小,所以给红点增加了一个宽高80dp的父layout,然后我们将touch小红点事件更改为touch小红点父layout,这样只要我们点击了小红点的父layout范围,都会添加GooView到WindowManager中。

接下来第二步,我们完成添加GooView到WindowManager中的代码。

由于我们的GooView初始添加是从listViewItem中红点的touch事件开始的,所以我们先完成listView adapter的实现。

  1. public class GooViewAapter extends BaseAdapter {
  2. private Context mContext;
  3. //记录已经remove的position
  4. private HashSet<Integer> mRemoved = new HashSet<Integer>();
  5. private List<String> list = new ArrayList<String>();
  6. public GooViewAapter(Context mContext, List<String> list) {
  7. super();
  8. this.mContext = mContext;
  9. this.list = list;
  10. }
  11. @Override
  12. public int getCount() {
  13. return list.size();
  14. }
  15. @Override
  16. public Object getItem(int position) {
  17. return list.get(position);
  18. }
  19. @Override
  20. public long getItemId(int position) {
  21. return position;
  22. }
  23. @Override
  24. public View getView(final int position, View convertView, ViewGroup parent) {
  25. if (convertView == null) {
  26. convertView = View.inflate(mContext, R.layout.list_item_goo, null);
  27. }
  28. ViewHolder holder = ViewHolder.getHolder(convertView);
  29. holder.mContent.setText(list.get(position));
  30. //item固定小红点layout
  31. LinearLayout pointLayout = holder.mPointLayout;
  32. //item固定小红点
  33. final TextView point = holder.mPoint;
  34. boolean visiable = !mRemoved.contains(position);
  35. pointLayout.setVisibility(visiable ? View.VISIBLE : View.GONE);
  36. if (visiable) {
  37. point.setText(String.valueOf(position));
  38. pointLayout.setTag(position);
  39. GooViewListener mGooListener = new GooViewListener(mContext, pointLayout) {
  40. @Override
  41. public void onDisappear(PointF mDragCenter) {
  42. super.onDisappear(mDragCenter);
  43. mRemoved.add(position);
  44. notifyDataSetChanged();
  45. Utils.showToast(mContext, "position " + position + " disappear.");
  46. }
  47. @Override
  48. public void onReset(boolean isOutOfRange) {
  49. super.onReset(isOutOfRange);
  50. notifyDataSetChanged();//刷新ListView
  51. Utils.showToast(mContext, "position " + position + " reset.");
  52. }
  53. };
  54. //在point父布局内的触碰事件都进行监听
  55. pointLayout.setOnTouchListener(mGooListener);
  56. }
  57. return convertView;
  58. }
  59. static class ViewHolder {
  60. public ImageView mImage;
  61. public TextView mPoint;
  62. public LinearLayout mPointLayout;
  63. public TextView mContent;
  64. public ViewHolder(View convertView) {
  65. mImage = (ImageView) convertView.findViewById(R.id.iv_head);
  66. mPoint = (TextView) convertView.findViewById(R.id.point);
  67. mPointLayout = (LinearLayout) convertView.findViewById(R.id.ll_point);
  68. mContent = (TextView) convertView.findViewById(R.id.tv_content);
  69. }
  70. public static ViewHolder getHolder(View convertView) {
  71. ViewHolder holder = (ViewHolder) convertView.getTag();
  72. if (holder == null) {
  73. holder = new ViewHolder(convertView);
  74. convertView.setTag(holder);
  75. }
  76. return holder;
  77. }
  78. }
  79. }

由于listview需要知道GooView的状态,所以我们在GooView中增加一个接口,用于listView回调处理后续的逻辑。

  1. interface OnDisappearListener {
  2. /**
  3. * GooView Disapper
  4. *
  5. * @param mDragCenter
  6. */
  7. void onDisappear(PointF mDragCenter);
  8. /**
  9. * GooView onReset
  10. *
  11. * @param isOutOfRange
  12. */
  13. void onReset(boolean isOutOfRange);
  14. }

新建一个实现了OnTouchListener以及OnDisappearListener 方法的的类,最后将这个实现类设置给item中的红点Layout。

  1. public class GooViewListener implements OnTouchListener, OnDisappearListener {
  2. private WindowManager mWm;
  3. private WindowManager.LayoutParams mParams;
  4. private GooView mGooView;
  5. private View pointLayout;
  6. private int number;
  7. private final Context mContext;
  8. private Handler mHandler;
  9. public GooViewListener(Context mContext, View pointLayout) {
  10. this.mContext = mContext;
  11. this.pointLayout = pointLayout;
  12. this.number = (Integer) pointLayout.getTag();
  13. mGooView = new GooView(mContext);
  14. mWm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
  15. mParams = new WindowManager.LayoutParams();
  16. mParams.format = PixelFormat.TRANSLUCENT;//使窗口支持透明度
  17. mHandler = new Handler(mContext.getMainLooper());
  18. }
  19. @Override
  20. public boolean onTouch(View v, MotionEvent event) {
  21. int action = MotionEventCompat.getActionMasked(event);
  22. // 当按下时,将自定义View添加到WindowManager中
  23. if (action == MotionEvent.ACTION_DOWN) {
  24. ViewParent parent = v.getParent();
  25. // 请求其父级View不拦截Touch事件
  26. parent.requestDisallowInterceptTouchEvent(true);
  27. int[] points = new int[2];
  28. //获取pointLayout在屏幕中的位置(layout的左上角坐标)
  29. pointLayout.getLocationInWindow(points);
  30. //获取初始小红点中心坐标
  31. int x = points[0] + pointLayout.getWidth() / 2;
  32. int y = points[1] + pointLayout.getHeight() / 2;
  33. // 初始化当前点击的item的信息,数字及坐标
  34. mGooView.setStatusBarHeight(Utils.getStatusBarHeight(v));
  35. mGooView.setNumber(number);
  36. mGooView.initCenter(x, y);
  37. //设置当前GooView消失监听
  38. mGooView.setOnDisappearListener(this);
  39. // 添加当前GooView到WindowManager
  40. mWm.addView(mGooView, mParams);
  41. pointLayout.setVisibility(View.INVISIBLE);
  42. }
  43. // 将所有touch事件转交给GooView处理
  44. mGooView.onTouchEvent(event);
  45. return true;
  46. }
  47. @Override
  48. public void onDisappear(PointF mDragCenter) {
  49. //disappear 下一步完成
  50. }
  51. @Override
  52. public void onReset(boolean isOutOfRange) {
  53. // 当dragPoint弹回时,去除该View,等下次ACTION_DOWN的时候再添加
  54. if (mWm != null && mGooView.getParent() != null) {
  55. mWm.removeView(mGooView);
  56. }
  57. }
  58. }

这样下来,我们基本上完成了大部分功能,现在还差最后一步,就是GooView超出范围消失后的处理,这里我们用一个帧动画来完成爆炸效果。

  1. public class BubbleLayout extends FrameLayout {
  2. Context context;
  3. public BubbleLayout(Context context) {
  4. super(context);
  5. this.context = context;
  6. }
  7. private int mCenterX, mCenterY;
  8. public void setCenter(int x, int y) {
  9. mCenterX = x;
  10. mCenterY = y;
  11. requestLayout();
  12. }
  13. @Override
  14. protected void onLayout(boolean changed, int left, int top, int right,
  15. int bottom) {
  16. View child = getChildAt(0);
  17. // 设置View到指定位置
  18. if (child != null && child.getVisibility() != GONE) {
  19. final int width = child.getMeasuredWidth();
  20. final int height = child.getMeasuredHeight();
  21. child.layout((int) (mCenterX - width / 2.0f), (int) (mCenterY - height / 2.0f)
  22. , (int) (mCenterX + width / 2.0f), (int) (mCenterY + height / 2.0f));
  23. }
  24. }
  25. }
  26. @Override
  27. public void onDisappear(PointF mDragCenter) {
  28. if (mWm != null && mGooView.getParent() != null) {
  29. mWm.removeView(mGooView);
  30. //播放气泡爆炸动画
  31. ImageView imageView = new ImageView(mContext);
  32. imageView.setImageResource(R.drawable.anim_bubble_pop);
  33. AnimationDrawable mAnimDrawable = (AnimationDrawable) imageView
  34. .getDrawable();
  35. final BubbleLayout bubbleLayout = new BubbleLayout(mContext);
  36. bubbleLayout.setCenter((int) mDragCenter.x, (int) mDragCenter.y - Utils.getStatusBarHeight(mGooView));
  37. bubbleLayout.addView(imageView, new FrameLayout.LayoutParams(
  38. android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
  39. android.widget.FrameLayout.LayoutParams.WRAP_CONTENT));
  40. mWm.addView(bubbleLayout, mParams);
  41. mAnimDrawable.start();
  42. // 播放结束后,删除该bubbleLayout
  43. mHandler.postDelayed(new Runnable() {
  44. @Override
  45. public void run() {
  46. mWm.removeView(bubbleLayout);
  47. }
  48. }, 501);
  49. }
  50. }

最后附上完整demo地址:https://github.com/Horrarndoo/GooView

本文作者:佚名
来源:51CTO

Android自定义控件:类QQ未读消息拖拽效果相关推荐

  1. android qq消息数 拖拽动画,史上最详细仿QQ未读消息拖拽粘性效果的实现

    好久没写文章了,前段时间由于项目代码重构忙了一段时间,现在终于有点时间了就为大家带来一篇关于动画学习的自定义View:类似QQ消息拖拽的效果. 其实QQ当时更新的时候我还没注意到这个小红点是可以拖拽的 ...

  2. Android 仿QQ未读消息拖拽删除粘性控件效果

    效果图: 分析  一 : 1.应用的地方:如未读数据的清除等 2.这个控件要实现哪些功能呢? 1)拖拽超出范围时,断开了,此时我们松手,图标消失 2)拖拽超出范围时,断开了,此时我们把图标移动回去,图 ...

  3. Android仿QQ消息拖拽效果(二)

    前言 本文参考辉哥贝塞尔曲线 - QQ消息汽包拖拽,前面我们使用二阶贝塞尔曲线绘制了拖拽圆点效果Android仿QQ消息拖拽效果(一)(二阶贝塞尔曲线使用),这里我们在此基础之上实现仿QQ消息拖拽爆炸 ...

  4. Android 桌面图标添加未读消息角标APP角标最佳实践

    Android 桌面图标添加未读消息角标APP角标最佳实践 本项目的完整演示代码 https://github.com/benchegnzhou/AndroidDevelomentArtDemo 最近 ...

  5. android+仿qq未读消息数量,仿qq自定义未读消息数显示角标

    66FF020E13B921CB19C7542F4801AF43.png 如图所示,我们需要实现的效果 在消息tab上,是一个组合的自定义view,具体实现如下 android:layout_widt ...

  6. Android app图标显示未读消息数

    转载请标明出处:http://blog.csdn.net/xx326664162/article/details/51082574 文章出自:薛瑄的博客 你也可以查看我的其他同类文章,也会让你有一定的 ...

  7. Android 仿新版QQ的tab下面拖拽标记为已读的效果

    可拖拽的红点,(仿新版QQ,tab下面拖拽标记为已读的效果),拖拽一定的距离可以消失回调. GitHub:DraggableFlagView(https://github.com/wangjiegul ...

  8. Android 仿QQ 聊天消息拖拽效果

    可拖拽的气泡效果 自定义view WateView public class WateView extends FrameLayout {//定义一个文本控件private TextView text ...

  9. Android应用程序显示未读消息计数

    在build.gradle下添加依赖 compile 'me.leolin:ShortcutBadger:1.1.16@aar' 显示 ShortcutBadger.applyCount(contex ...

最新文章

  1. 策略模式——Strategy
  2. C#中方法的参数四种类型(值参数、ref、out、params)详解
  3. oracle监听 客户 实例,oracle 数据库实例 监听
  4. Notepad++安装教程
  5. EEPROM和flash的区别
  6. prestashop 隐藏 index.php,删除PrestaShop中的供应商和制造商页面
  7. ImportError: libjpeg.so.62: cannot open shared object file: No such file or directory
  8. php file_get_contents 效率,php 浅析file_get_contents、curl 的效率和稳定性
  9. Linux top 使用技巧
  10. UnityShader4:UnityShader的形式
  11. Ruby+watir自动化测试中实现识别验证码图片
  12. MVC三层架构详细图
  13. 通信接口——RS-232与RS-422及RS-485三者之间的特性与区别
  14. Cesium结合kriging.js制作降雨等值面
  15. 计算机无法安装操作系统的原因,关于电脑无法安装IE浏览器的原因有哪些
  16. 极速office(Word)文件怎么在方框里面打对勾
  17. 用计算机弹奏全球变冷,《全球变冷,钢琴谱》许嵩(五线谱 钢琴曲 指法)-弹吧|蛐蛐钢琴网...
  18. python代码怎么修改_python修改微信和支付宝步数的示例代码
  19. MAYA XGen创建毛发时报错找不到过程“XgCreateDescription“的解决方法
  20. 自定义Android键盘

热门文章

  1. 什么是AnTi防御-无限防方案?能帮助游戏解决哪些攻击问题?
  2. NSTimeInterval 的使用
  3. python画立体地球_创建可旋转的三维地球
  4. 常用技术指标之一文读懂BOLL布林线指标
  5. mastering mysql_Mastering The Faster Web with PHP, MySQL, and JavaScript
  6. 此对象非彼对象(面向对象)1
  7. docker 快鸟_Elastic-Job原理分析(version:2.1.4)
  8. 在一款恋爱模拟游戏中,男主角进入了某个女主角的线路,现在遵循“与其约会,使其娇羞”的战略,共有9个约会场所提供使用。其中,有四个约会场景,较为浪漫,男主可以取得好感度+2或者好感度+0,五个约会场景较
  9. 关于史考特证券(scottrade Inc)资金转出的手续费问题
  10. 分词工具 java_IK分词工具的使用(java)