在坐地铁的时候,能看到有些地铁上是有地铁行进动画和站点到达动画的,最近在做项目的时候,就有一个类似这样的需求,不同的是展示的点有限制,多出来的点是需要是折贴起来的,当需要展示时再拉出来,大致动画如下:

看到这样一个动画,你有什么想法呢?对于这个动画,我有一个同事使用的是RecycleView去做的,做出来后差不多有十几个类,里面的逻辑还是比较复杂的,由于同事离职,这里面还有一些问题存在,由我接手修改,确实不太好改,没办法,尝试自己撸一个。对于这样一个动画,我首先想到的是使用自定义View来解决。先来说一下绘制这个View的大致思路:先绘制静态的,在绘制动态的。
1、如何绘制静态的呢,这个比较简单,不过这里需要考虑一个问题,站点抽出是向左抽出的,所以绘制时应该从右边开始画,主要的界面是由圆还有线绘制成的,这些都很简单,现在主要来说说这写点线位置的计算,首先一开始左右位置的间隙是对称的,这里可以根据预先设置的点的个数,根据屏宽和预先设置的参数计算出线的长短,这样就可以画出这些点还有线了,点还有线绘制完后,就差文字及其背景了,文字这个不多说,背景其实也就是一条线,只不过是比较宽而已。
2、比较难的是动态绘制的处理,可以看出,点一次可以拉出1~3个,这里将一个点和一条线看做是一段长,这里先上一段代码:

private void initAnimator() {animator = new ValueAnimator();animator.addUpdateListener(animation -> {changeX = (float) animation.getAnimatedValue();if ((int) (changeX / lineWithdotWidth) == flag) {headPositionIndex++;flag++;}changeX = changeX % lineWithdotWidth;isScrolling = true;invalidate();});animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);isScrolling = false;flag = 1;}});}

后面动画用到的主要就是这个changeX,根据这个changX去绘制点和线,由于拉出的过程都是在一个点和线之间的距离变化的,所以这个changeX就是在这个范围内变化的,大致的思路就是这样,当然里面还有好多细节需要去处理,代码主要分为三个类,其中两个是处理点位数据的,比较简单:

public class IndicatorPositionDatas {private List<PositionData> positionList = new ArrayList<>();public IndicatorPositionDatas(List<String> list) {boolean isTextUp;int size = list.size();for (int i = 0; i < size-1; i++) {isTextUp = (i % 2 == 0);PositionData positionData = new PositionData(list.get(i),isTextUp,i);positionList.add(positionData);}PositionData positionData = new PositionData(list.get(size-1),true,size-1);positionList.add(positionData);}public PositionData getLastPosition(){return positionList.get(positionList.size()-1);}public PositionData getCurrentPosition(int position){return positionList.get(position);}public int size(){return positionList.size();}}
public class PositionData {private String positionText;private boolean isTextUp;private int position;public PositionData(String positionText, boolean isTextUp,int position) {this.positionText = positionText;this.isTextUp = isTextUp;this.position = position;}public String getText() {return positionText;}public boolean isTextUp() {return isTextUp;}public int getPosition() {return position;}public void setPosition(int position) {this.position = position;}
}

接下来就是自定义的View类:

public class IndicatorViewGroup extends View {private static final String TAG = "IndicatorViewGroup";private Paint mPaintText;private Paint mPaintLine;private Paint mPaintTextBg;private Paint mPaintDot;private Paint mPaintLoopDot;private int lineNoWalkColor = 0xFF219BFF;private int lineWalkedColor = 0xFF999999;private int dotStartColor = 0xFFFCB300;private int dotEndColor = 0xFFEA0075;private int textBackground = 0xFFF4F4F9;private int dotWidthAndHeight;private int lineLength;private int leftRightPadding;private int lineWidth;private int textBgWidth;//绘制文字背景时,背景距离dot的距离private int textBgMarginDot;//绘制文字时定位的Y方向坐标private float textTopBaseline;private float textBottomBaseline;//绘制文字背景定位的中心线private float textBgTopCenter;private float textBgBottomCenter;private float changeX = 0;private int animatorTime = 4000;private int dotFlashTime = 500;private ValueAnimator animator;private int textSize = 16;private IndicatorPositionDatas positionDatas;private int headPositionIndex = 0;private int arrivePosition = 0;private String textMore = "更多(%d)";//绘制在上边文本的位置信息private int dotTopPosition;//绘制下边文本的位置信息private int dotBottomPosition;private int flag = 1;private boolean isScrolling;//view的垂直居中位置private int centerY;private int lineWithdotWidth;private boolean isWalking = false;private long timeFlag;//外圆环的宽度private int loopDotStroke;//绘制点所需要的参数,cx是点的中心点private float cx;private float dotRadius;private float loopDotRadius;private float lineWithCircleGap;private float dotOffset;/*** 去往目的点的途中*/public void arriveNext() {if (!isWalking && arrivePosition == positionDatas.size() - 1) {Toast.makeText(getContext(), "已经到终点了", Toast.LENGTH_SHORT).show();return;}if (isWalking) {isWalking = false;if (headPositionIndex + 3 == arrivePosition) {if (arrivePosition < positionDatas.size() - 3) {startAnimator();}}return;}timeFlag = System.currentTimeMillis();isWalking = true;arrivePosition++;invalidate();}/*** 到达目的点*/public void arriveTo() {if (!isWalking && arrivePosition == positionDatas.size() - 1) {Toast.makeText(getContext(), "已经到终点了", Toast.LENGTH_SHORT).show();return;}if (isWalking) {isWalking = false;if (headPositionIndex + 3 == arrivePosition) {if (arrivePosition < positionDatas.size() - 3) {startAnimator();}}}}/*** 开启展开动画*/public void startAnimator() {int count = isScrolling ? 6 : 5;int moreCount = positionDatas.size() - headPositionIndex - count;if (moreCount == 3) {animator.setFloatValues(2 * lineWithdotWidth);animator.setDuration(animatorTime * 2 / 3);} else if (moreCount == 2) {animator.setFloatValues(lineWithdotWidth);animator.setDuration(animatorTime / 3);} else {animator.setFloatValues(3 * lineWithdotWidth);animator.setDuration(animatorTime);}animator.start();}/*** @param arrivePosition 所在的位置点*/public void setArrivePosition(int arrivePosition) {this.arrivePosition = arrivePosition;}/*** @param list 点位数据*/public void setPositionDatas(ArrayList<String> list) {positionDatas = new IndicatorPositionDatas(list);}/*** @param size 位置点上文字的大小*/public void setTextSize(int size) {textSize = size;}/*** @param lineWidth 路线线条的宽度*/public void setLineWidth(int lineWidth) {this.lineWidth = lineWidth;}/*** @param textBgWidth 文字背景的宽度*/public void setTextBgWidth(int textBgWidth) {this.textBgWidth = textBgWidth;}/*** @param marginDot 文字距离原点的距离*/public void setTextBgMarginDot(int marginDot) {textBgMarginDot = marginDot;}/*** @param animatorTime 设置展开三个点所需的时间,单位是ms*/public void setAnimatorTime(int animatorTime) {this.animatorTime = animatorTime;}/*** @param dotFlashTime 设置点位闪动的时间间隔*/public void setDotFlashTime(int dotFlashTime) {this.dotFlashTime = dotFlashTime;}/*** @param lineWithCircleGap 线与点之间的间隔*/public void setLineWithCircleGap(float lineWithCircleGap) {this.lineWithCircleGap = lineWithCircleGap;}public IndicatorViewGroup(Context context) {super(context);}public IndicatorViewGroup(Context context, AttributeSet attrs) {this(context, attrs, 0);}public IndicatorViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initParams();initDotParams();initPaint();initAnimator();}private void initPaint() {mPaintText = new Paint();mPaintText.setAntiAlias(true);mPaintText.setColor(Color.BLACK);mPaintText.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSize, getResources().getDisplayMetrics()));mPaintLine = new Paint();mPaintLine.setAntiAlias(true);mPaintLine.setColor(lineNoWalkColor);mPaintLine.setStrokeWidth(lineWidth);mPaintLine.setStyle(Paint.Style.FILL);mPaintLine.setStrokeCap(Paint.Cap.ROUND);mPaintTextBg = new Paint();mPaintTextBg.setAntiAlias(true);mPaintTextBg.setColor(textBackground);mPaintTextBg.setStrokeWidth(textBgWidth);mPaintTextBg.setStyle(Paint.Style.FILL);mPaintTextBg.setStrokeCap(Paint.Cap.ROUND);mPaintDot = new Paint();mPaintDot.setAntiAlias(true);mPaintDot.setColor(lineNoWalkColor);mPaintDot.setStyle(Paint.Style.FILL);mPaintLoopDot = new Paint();mPaintLoopDot.setAntiAlias(true);mPaintLoopDot.setColor(Color.parseColor("#FFFFFF"));mPaintLoopDot.setStrokeWidth(loopDotStroke);mPaintLoopDot.setStyle(Paint.Style.STROKE);}private void initParams() {leftRightPadding = (int) px2Dp(27);lineWidth = (int) px2Dp(10);textBgWidth = (int) px2Dp(30);textBgMarginDot = (int) px2Dp(5);dotRadius = px2Dp(14);lineWithCircleGap = px2Dp(13);loopDotStroke = (int) px2Dp(3);dotOffset = px2Dp(6);}private float px2Dp(int px) {return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, px, getContext().getResources().getDisplayMetrics());}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = MeasureSpec.getSize(widthMeasureSpec);lineLength = (width - 2 * leftRightPadding - 6 * dotWidthAndHeight) / 5;lineWithdotWidth = dotWidthAndHeight + lineLength;int heightMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = dotWidthAndHeight + textBgMarginDot * 2 + textBgWidth * 2 + (int) px2Dp(10);if (heightSize > MeasureSpec.getSize(heightMeasureSpec)) {heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();initArrivePosition();}/*** 初始化所在的位置点是否需要展开*/private void initArrivePosition() {if (!isMorePosition() || arrivePosition == 0) return;if (arrivePosition % 3 == 0) {headPositionIndex = (arrivePosition - 1) / 3 * 3;postDelayed(this::startAnimator, 1000);}}private boolean isMorePosition() {return positionDatas.size() > 6;}private void initDotParams() {dotWidthAndHeight = (int) (dotRadius + lineWithCircleGap) * 2;loopDotRadius = dotRadius + loopDotStroke / 2f;cx = dotWidthAndHeight / 2f;}private void initAnimator() {animator = new ValueAnimator();animator.addUpdateListener(animation -> {changeX = (float) animation.getAnimatedValue();if ((int) (changeX / lineWithdotWidth) == flag) {headPositionIndex++;flag++;}changeX = changeX % lineWithdotWidth;isScrolling = true;invalidate();});animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);isScrolling = false;flag = 1;}});}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);centerY = getHeight() / 2;dotTopPosition = centerY - dotWidthAndHeight / 2;dotBottomPosition = centerY + dotWidthAndHeight / 2;mPaintText.measureText(positionDatas.getLastPosition().getText());Paint.FontMetrics fm = mPaintText.getFontMetrics();textTopBaseline = dotTopPosition - fm.descent - textBgMarginDot;textBottomBaseline = dotBottomPosition + fm.descent - fm.ascent + textBgMarginDot - px2Dp(2);textBgTopCenter = dotTopPosition - (fm.bottom - fm.top) / 2 - textBgMarginDot;textBgBottomCenter = dotBottomPosition + (fm.bottom - fm.top) / 2 + textBgMarginDot;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawPosition(canvas);}private void drawPosition(Canvas canvas) {if (isMorePosition()) {canvas.translate(getWidth() - dotWidthAndHeight - leftRightPadding + dotOffset, 0);} else {canvas.translate(getWidth() - dotWidthAndHeight - leftRightPadding - (6 - positionDatas.size()) * lineWithdotWidth, 0);}drawDot(canvas, positionDatas.getLastPosition());translateLine(canvas);if (arrivePosition == positionDatas.size() - 1) {mPaintLine.setColor(lineWalkedColor);} else {mPaintLine.setColor(lineNoWalkColor);}drawLine(canvas, positionDatas.getLastPosition());int dotIndex = 3;translateBit(canvas);if (isMorePosition()) {//绘制拉出的那个点canvas.translate(-2 * dotOffset, 0);if (changeX != 0) {unfoldPosition(canvas);}} else {dotIndex = positionDatas.size() - 3;}//绘制倒数第二个点drawDot(canvas, positionDatas.getCurrentPosition(positionDatas.size() - 2));int index;for (int i = dotIndex; 0 <= i; i--) {translateLine(canvas);index = headPositionIndex + i;int lineColor = arrivePosition <= index ? lineNoWalkColor : lineWalkedColor;mPaintLine.setColor(lineColor);PositionData currentPosition = positionDatas.getCurrentPosition(index);drawLine(canvas, currentPosition);translateBit(canvas);drawDot(canvas, currentPosition);}if (headPositionIndex != 0) {mPaintLine.setColor(lineWalkedColor);mPaintLine.setShader(null);canvas.drawLine(-lineLength / 2f, centerY, 0, centerY, mPaintLine);}if (!isScrolling) {invalidate();}}private void unfoldPosition(Canvas canvas) {canvas.translate(-changeX, 0);mPaintDot.setColor(lineNoWalkColor);canvas.drawCircle(cx, centerY, dotRadius, mPaintDot);canvas.drawCircle(cx, centerY, loopDotRadius, mPaintLoopDot);if (changeX > dotWidthAndHeight) {float stopX;if (changeX > dotWidthAndHeight + lineLength) {stopX = dotWidthAndHeight + lineLength;} else {stopX = changeX + 10;}canvas.drawLine(dotWidthAndHeight, centerY, stopX, centerY, mPaintLine);}if (lineLength > changeX) {int alpha = (int) (changeX / lineLength * 255);mPaintText.setAlpha(alpha);}drawText(canvas, positionDatas.getCurrentPosition(headPositionIndex + 4));mPaintText.setAlpha(255);}private void translateLine(Canvas canvas) {canvas.translate(-lineLength, 0);}private void translateBit(Canvas canvas) {canvas.translate(-dotWidthAndHeight, 0);}//绘制线以及移动时相应的动画private float offsetFlashX;private void drawLine(Canvas canvas, PositionData msg) {if (msg.getPosition() == arrivePosition - 1 || (arrivePosition == positionDatas.size() - 1 && msg.getPosition() == positionDatas.size() - 1)) {if (isWalking) {mPaintLine.setColor(dotStartColor);LinearGradient backGradient = new LinearGradient(-lineLength + offsetFlashX, 0, offsetFlashX, 0, new int[]{dotStartColor, 0xffffffff, dotStartColor}, null, Shader.TileMode.CLAMP);mPaintLine.setShader(backGradient);}} else {mPaintLine.setShader(null);}offsetFlashX = offsetFlashX + 1f;if (offsetFlashX > lineLength * 2) offsetFlashX = 0;canvas.drawLine(0, centerY, lineLength, centerY, mPaintLine);}private void drawDot(Canvas canvas, PositionData msg) {int position = msg.getPosition();long time = System.currentTimeMillis();long toLastTime = time - timeFlag;Log.d(TAG, "drawDot: toLastTime = " + toLastTime);if (position == arrivePosition) {if (toLastTime / dotFlashTime % 2 == 1) {mPaintDot.setColor(dotStartColor);} else {mPaintDot.setColor(0x00000000);}} else {if (position == 0 && arrivePosition == 0) {mPaintDot.setColor(dotStartColor);} else if (position == positionDatas.size() - 1) {mPaintDot.setColor(dotEndColor);} else {if (position < arrivePosition) {mPaintDot.setColor(lineWalkedColor);} else {mPaintDot.setColor(lineNoWalkColor);}}}int count = isScrolling ? 6 : 5;int moreCount = positionDatas.size() - headPositionIndex - count;if (position == positionDatas.size() - 2) {if (isMorePosition()) {//绘制倒数第二个点drawMoreDot(canvas, moreCount);} else {canvas.drawCircle(cx + changeX, centerY, dotRadius, mPaintDot);canvas.drawCircle(cx + changeX, centerY, loopDotRadius, mPaintLoopDot);}if ((headPositionIndex + 6) < positionDatas.size()) {String textName = String.format(textMore, moreCount);float textWidth = mPaintText.measureText(textName);//绘制文字背景色canvas.drawLine(changeX + (-textWidth + dotWidthAndHeight) / 2 + dotOffset, textBgTopCenter,changeX + (textWidth + dotWidthAndHeight) / 2 + dotOffset, textBgTopCenter, mPaintTextBg);canvas.drawText(textName, (-textWidth + dotWidthAndHeight) / 2 + changeX + dotOffset, textTopBaseline, mPaintText);} else {float textWidth = mPaintText.measureText(msg.getText());//绘制文字背景if (msg.getPosition() == arrivePosition) {mPaintTextBg.setColor(dotStartColor);} else {mPaintTextBg.setColor(textBackground);}if (msg.isTextUp()) {canvas.drawLine((-textWidth + dotWidthAndHeight) / 2 + dotOffset, textBgTopCenter,(textWidth + dotWidthAndHeight) / 2, textBgTopCenter, mPaintTextBg);} else {canvas.drawLine((-textWidth + dotWidthAndHeight) / 2 + dotOffset, textBgBottomCenter,(textWidth + dotWidthAndHeight) / 2, textBgBottomCenter, mPaintTextBg);}//绘制文字if (msg.isTextUp()) {canvas.drawText(msg.getText(), (-textWidth + dotWidthAndHeight) / 2 + dotOffset, textTopBaseline, mPaintText);} else {canvas.drawText(msg.getText(), (-textWidth + dotWidthAndHeight) / 2 + dotOffset, textBottomBaseline, mPaintText);}}} else {canvas.drawCircle(cx, centerY, dotRadius, mPaintDot);canvas.drawCircle(cx, centerY, loopDotRadius, mPaintLoopDot);drawText(canvas, msg);}}private void drawMoreDot(Canvas canvas, int moreCount) {float factor1 = 2;float factor2 = 0;if (moreCount == 2) {factor1 = 2 - changeX / lineWithdotWidth / 2;factor2 = changeX / lineWithdotWidth / 2;if (changeX == 0) {factor1 = 1.5f;factor2 = 0.5f;}}if (moreCount == 1) {if ((headPositionIndex + 6) < positionDatas.size()) {factor1 = 1.5f - changeX / lineWithdotWidth / 2;factor2 = changeX / lineWithdotWidth / 2 + 0.5f;} else {factor1 = factor2 = 1;}}if (factor1 != 1) {canvas.drawCircle(cx + changeX + factor1 * dotOffset, centerY, dotRadius, mPaintDot);canvas.drawCircle(cx + changeX + factor1 * dotOffset, centerY, loopDotRadius, mPaintLoopDot);}canvas.drawCircle(cx + changeX + dotOffset, centerY, dotRadius, mPaintDot);canvas.drawCircle(cx + changeX + dotOffset, centerY, loopDotRadius, mPaintLoopDot);if (factor2 != 1) {canvas.drawCircle(cx + changeX + factor2 * dotOffset, centerY, dotRadius, mPaintDot);canvas.drawCircle(cx + changeX + factor2 * dotOffset, centerY, loopDotRadius, mPaintLoopDot);}}private void drawText(Canvas canvas, PositionData msg) {float textWidth = mPaintText.measureText(msg.getText());drawTextBackground(canvas, textWidth, msg);if (msg.isTextUp()) {canvas.drawText(msg.getText(), (-textWidth + dotWidthAndHeight) / 2, textTopBaseline, mPaintText);} else {canvas.drawText(msg.getText(), (-textWidth + dotWidthAndHeight) / 2, textBottomBaseline, mPaintText);}}private void drawTextBackground(Canvas canvas, float textWidth, PositionData msg) {if (msg.getPosition() == arrivePosition) {mPaintTextBg.setColor(dotStartColor);} else {mPaintTextBg.setColor(textBackground);}if (msg.isTextUp()) {canvas.drawLine((-textWidth + dotWidthAndHeight) / 2, textBgTopCenter,(textWidth + dotWidthAndHeight) / 2, textBgTopCenter, mPaintTextBg);} else {canvas.drawLine((-textWidth + dotWidthAndHeight) / 2, textBgBottomCenter,(textWidth + dotWidthAndHeight) / 2, textBgBottomCenter, mPaintTextBg);}}}

代码到这就算是完成了,代码量不多,用起来也很简单,首先就是在xml中进行添加:

    <com.example.ubt.myapplication.view.IndicatorViewGroupandroid:id="@+id/iv_animator"android:layout_width="match_parent"android:layout_height="wrap_content"></com.example.ubt.myapplication.view.IndicatorViewGroup>

高度这里可以指定高度,但都是会居中绘制的,最后就是在Activity中进行使用了,也比较简单:

     IndicatorViewGroup ivAnimator = (IndicatorViewGroup) findViewById(R.id.iv_animator);ivAnimator.setPositionDatas(list);findViewById(R.id.btn_start).setOnClickListener(v->ivAnimator.arriveNext());

这样完成后,点击按钮就可以动起来了,代码中还提供了一个arriveTo()方法,为了方便调试,直接将这个方法添加到了arriveNext()中,如果需要使用两个方法,直接把arriveNext()中相同的代码去掉即可,为了整体的视觉感,这里建议将屏幕设置成横屏。

android仿地铁行进线路图相关推荐

  1. php仿微信底部菜单,Android实现简单底部导航栏 Android仿微信滑动切换效果

    Android仿微信滑动切换最终实现效果: 大体思路: 1. 主要使用两个自定义View配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标; 2. 底部导航栏 ...

  2. android tab 悬停效果代码,Android 仿腾讯应用宝 之 Toolbar +Scroolview +tab滑动悬停效果...

    Android 仿腾讯应用宝 之 Toolbar +Scroolview +tab滑动悬停效果 来源:互联网 作者:佚名 时间:2015-02-10 15:36 Android 仿腾讯应用宝 之 To ...

  3. Android 仿PhotoShop调色板应用(三) 主体界面绘制

    版权声明:本文为博主原创文章,未经博主允许不得转载. Android 仿PhotoShop调色板应用(三) 主体界面绘制    关于PhotoShop调色板应用的实现我总结了两个最核心的部分:   1 ...

  4. android仿qq聊天项目点评,android 实现qq聊天对话界面效果

    [实例简介] Android UI[android 仿微信.QQ聊天,带表情,可翻页,带翻页拖动缓冲] 博客介绍http://blog.csdn.net/lnb333666/article/detai ...

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

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

  6. android rebound平移,Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout

    Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout 前言 IOS 拖拽回弹给用户的体验不得不赞然后 Android 原生的 API 各种不支持, 于是乎出现的很多仿 IO ...

  7. Android 仿微信小视频录制

    Android 仿微信小视频录制 WechatShortVideo和WechatShortVideo文章

  8. Android仿QQ侧滑菜单

    先上效果图: GIF图有点模糊,源码已上传Github:Android仿QQ侧滑菜单 ####整体思路: 自定义ItemView的根布局(SwipeMenuLayout extends LinearL ...

  9. Android自定义弹窗模仿微信,Android仿微信右上角点击加号弹出PopupWindow

    本文实例为大家分享了Android仿微信右上角点击加号弹出展示的具体代码,供大家参考,具体内容如下 一.要弹出的布局,随便设计 android:layout_width="match_par ...

最新文章

  1. R语言Hosmer-Lemeshow检验得到校准曲线的P值实战
  2. 【步态识别】基于深度学习的步态识别系统的MATLAB仿真,包括ALEXNET,改进CNN,GOOGLENET
  3. Python入门学习---第三天
  4. oracle 快捷 企业,Oracle自治数据库提供APEX 20.1,助企业快速构建应用
  5. wordpress迁移后,伪静态404解决方法
  6. Android 屏幕适配攻略(三)单位dp与sp
  7. Python批量替换掉某些值为新的值
  8. 域控制器部署组策略,立即下发强制更新,显示“远程过程调用被取消”,错误代码 8007071a;以及RPC服务器不可用,800706ba【解决方案】
  9. 为什么越来越多的人直接入住毛坯房?有什么优缺点?
  10. 海思3519A配置NFS文件系统(永久)
  11. SaltStack 拉取和推送文件
  12. 阿里云银行关键业务破冰 邢台银行首家
  13. 基于分数阶傅里叶变换的chirp信号检测与参数估计(原理附代码)
  14. 禁用驱动数字签名验证
  15. java软件官网下载汇总——JDK,eclipse,mysql,maven,idea,Git,oracle
  16. web视频(点播/直播)播放器选型
  17. eclipes 快捷键操作:
  18. 《Windows 8 权威指南》——2.7 降低功耗,延长续航时间才是王道
  19. HTML5实现的树叶飘落动画特效
  20. 华为p10 android几,华为p10国行版和海外版有什么区别 配置参数对比评测

热门文章

  1. 运行linux命令并返回结果
  2. 厦门理工c语言课程设计,厦门理工学院+C语言+课程设计
  3. 第六次网页前端培训(JS)
  4. jQuery 常规选择器
  5. cdo (Climate Data Operators ) 常用命令介绍:(查看文件信息、多文件合并、数据裁剪、数据插值、数据计算。。)
  6. android手机和平板,Android手机和平板电脑总体性能排名
  7. QTL 容器 与 STL(1)- 写时复制
  8. Arctime字幕添加
  9. 多个自变量因变量中介变量做Amos
  10. 创客匠人助力内容创业者提升市场竞争力