Android之SurfaceView

SurfaceView也是继承了View,但是我们并不需要去实现它的draw方法来绘制自己,为什么呢?
因为它和View有一个很大的区别,View在UI线程去更新自己;而SurfaceView则在一个子线程中去更新自己;这也显示出了它的优势,当制作游戏等需要不断刷新View时,因为是在子线程,避免了对UI线程的阻塞。
知道了优势以后,你会想那么不使用draw方法,哪来的canvas使用呢?
大家都记得更新View的时候draw方法提供了一个canvas,SurfaceView内部内嵌了一个专门用于绘制的Surface,而这个Surface中包含一个Canvas。
有了Canvas,我们如何获取呢?
SurfaceView里面有个getHolder方法,我们可以获取一个SurfaceHolder。通过SurfaceHolder可以监听SurfaceView的生命周期以及获取Canvas对象。

通常用法

public class SurfaceViewTemplate extends SurfaceView implements Callback, Runnable
{private SurfaceHolder mHolder;/*** 与SurfaceHolder绑定的Canvas*/private Canvas mCanvas;/*** 用于绘制的线程*/private Thread t;/*** 线程的控制开关*/private boolean isRunning;public SurfaceViewTemplate(Context context){this(context, null);}public SurfaceViewTemplate(Context context, AttributeSet attrs){super(context, attrs);mHolder = getHolder();mHolder.addCallback(this);// setZOrderOnTop(true);// 设置画布 背景透明// mHolder.setFormat(PixelFormat.TRANSLUCENT);//设置可获得焦点setFocusable(true);setFocusableInTouchMode(true);//设置常亮this.setKeepScreenOn(true);}@Overridepublic void surfaceCreated(SurfaceHolder holder){// 开启线程isRunning = true;t = new Thread(this);t.start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height){// TODO Auto-generated method stub}@Overridepublic void surfaceDestroyed(SurfaceHolder holder){// 通知关闭线程isRunning = false;}@Overridepublic void run(){// 不断的进行drawwhile (isRunning){draw();}}private void draw(){try{// 获得canvasmCanvas = mHolder.lockCanvas();if (mCanvas != null){// drawSomething..}} catch (Exception e){} finally{if (mCanvas != null)mHolder.unlockCanvasAndPost(mCanvas);}}
}

结合上面我们的介绍,我们在构造中通过getHolder拿到SurfaceHolder对象,然后设置一个addCallback回调,去监听SurfaceView的生命周期,生命周期有三个方法,分别为create,change,destory;我们一般在create里面进行初始化的一些操作,然后开启线程;在destroy里面设置关闭线程;
所有的绘制流程都是线程的run方法里面,可以看到我们的draw方法。
注意下,我们在draw里面进行了try catch然后很多的判空,主要是因为,当用户点击back或者按下home键以后,surfaceview会被销毁;
mHolder.lockCanvas();返回的就是null了,所以为了避免造成空指针错误,我们各种判null,甚至还加了个try catch。

实例 抽奖转盘

效果图

代码如下

package com.zhy.view;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;import com.zhy.demo_zhy_06_choujiangzhuanpan.R;public class LuckyPanView extends SurfaceView implements Callback, Runnable
{private SurfaceHolder mHolder;/*** 与SurfaceHolder绑定的Canvas*/private Canvas mCanvas;/*** 用于绘制的线程*/private Thread t;/*** 线程的控制开关*/private boolean isRunning;/*** 抽奖的文字*/private String[] mStrs = new String[] { "单反相机", "IPAD", "恭喜发财", "IPHONE","妹子一只", "恭喜发财" };/*** 每个盘块的颜色*/private int[] mColors = new int[] { 0xFFFFC300, 0xFFF17E01, 0xFFFFC300,0xFFF17E01, 0xFFFFC300, 0xFFF17E01 };/*** 与文字对应的图片*/private int[] mImgs = new int[] { R.drawable.danfan, R.drawable.ipad,R.drawable.f040, R.drawable.iphone, R.drawable.meizi,R.drawable.f040 };/*** 与文字对应图片的bitmap数组*/private Bitmap[] mImgsBitmap;/*** 盘块的个数*/private int mItemCount = 6;/*** 绘制盘块的范围*/private RectF mRange = new RectF();/*** 圆的直径*/private int mRadius;/*** 绘制盘快的画笔*/private Paint mArcPaint;/*** 绘制文字的画笔*/private Paint mTextPaint;/*** 滚动的速度*/private double mSpeed;private volatile float mStartAngle = 0;/*** 是否点击了停止*/private boolean isShouldEnd;/*** 控件的中心位置*/private int mCenter;/*** 控件的padding,这里我们认为4个padding的值一致,以paddingleft为标准*/private int mPadding;/*** 背景图的bitmap*/private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.bg2);/*** 文字的大小*/private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());public LuckyPanView(Context context){this(context, null);}public LuckyPanView(Context context, AttributeSet attrs){super(context, attrs);mHolder = getHolder();mHolder.addCallback(this);// setZOrderOnTop(true);// 设置画布 背景透明// mHolder.setFormat(PixelFormat.TRANSLUCENT);setFocusable(true);setFocusableInTouchMode(true);this.setKeepScreenOn(true);}/*** 设置控件为正方形*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);int width = Math.min(getMeasuredWidth(), getMeasuredHeight());// 获取圆形的直径mRadius = width - getPaddingLeft() - getPaddingRight();// padding值mPadding = getPaddingLeft();// 中心点mCenter = width / 2;setMeasuredDimension(width, width);}@Overridepublic void surfaceCreated(SurfaceHolder holder){// 初始化绘制圆弧的画笔mArcPaint = new Paint();mArcPaint.setAntiAlias(true);mArcPaint.setDither(true);// 初始化绘制文字的画笔mTextPaint = new Paint();mTextPaint.setColor(0xFFffffff);mTextPaint.setTextSize(mTextSize);// 圆弧的绘制范围mRange = new RectF(getPaddingLeft(), getPaddingLeft(), mRadius+ getPaddingLeft(), mRadius + getPaddingLeft());// 初始化图片mImgsBitmap = new Bitmap[mItemCount];for (int i = 0; i < mItemCount; i++){mImgsBitmap[i] = BitmapFactory.decodeResource(getResources(),mImgs[i]);}// 开启线程isRunning = true;t = new Thread(this);t.start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height){// TODO Auto-generated method stub}@Overridepublic void surfaceDestroyed(SurfaceHolder holder){// 通知关闭线程isRunning = false;}@Overridepublic void run(){// 不断的进行drawwhile (isRunning){long start = System.currentTimeMillis();draw();long end = System.currentTimeMillis();try{if (end - start < 50){Thread.sleep(50 - (end - start));}} catch (InterruptedException e){e.printStackTrace();}}}private void draw(){try{// 获得canvasmCanvas = mHolder.lockCanvas();if (mCanvas != null){// 绘制背景图drawBg();/*** 绘制每个块块,每个块块上的文本,每个块块上的图片*/float tmpAngle = mStartAngle;float sweepAngle = (float) (360 / mItemCount);for (int i = 0; i < mItemCount; i++){// 绘制快快mArcPaint.setColor(mColors[i]);
//                  mArcPaint.setStyle(Style.STROKE);mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true,mArcPaint);// 绘制文本drawText(tmpAngle, sweepAngle, mStrs[i]);// 绘制IcondrawIcon(tmpAngle, i);tmpAngle += sweepAngle;}// 如果mSpeed不等于0,则相当于在滚动mStartAngle += mSpeed;// 点击停止时,设置mSpeed为递减,为0值转盘停止if (isShouldEnd){mSpeed -= 1;}if (mSpeed <= 0){mSpeed = 0;isShouldEnd = false;}// 根据当前旋转的mStartAngle计算当前滚动到的区域calInExactArea(mStartAngle);}} catch (Exception e){e.printStackTrace();} finally{if (mCanvas != null)mHolder.unlockCanvasAndPost(mCanvas);}}/*** 根据当前旋转的mStartAngle计算当前滚动到的区域 绘制背景,不重要,完全为了美观*/private void drawBg(){mCanvas.drawColor(0xFFFFFFFF);mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding / 2,mPadding / 2, getMeasuredWidth() - mPadding / 2,getMeasuredWidth() - mPadding / 2), null);}/*** 根据当前旋转的mStartAngle计算当前滚动到的区域* * @param startAngle*/public void calInExactArea(float startAngle){// 让指针从水平向右开始计算float rotate = startAngle + 90;rotate %= 360.0;for (int i = 0; i < mItemCount; i++){// 每个的中奖范围float from = 360 - (i + 1) * (360 / mItemCount);float to = from + 360 - (i) * (360 / mItemCount);if ((rotate > from) && (rotate < to)){Log.d("TAG", mStrs[i]);return;}}}/*** 绘制图片* * @param startAngle* @param sweepAngle* @param i*/private void drawIcon(float startAngle, int i){// 设置图片的宽度为直径的1/8int imgWidth = mRadius / 8;float angle = (float) ((30 + startAngle) * (Math.PI / 180));int x = (int) (mCenter + mRadius / 2 / 2 * Math.cos(angle));int y = (int) (mCenter + mRadius / 2 / 2 * Math.sin(angle));// 确定绘制图片的位置Rect rect = new Rect(x - imgWidth / 2, y - imgWidth / 2, x + imgWidth/ 2, y + imgWidth / 2);mCanvas.drawBitmap(mImgsBitmap[i], null, rect, null);}/*** 绘制文本* * @param rect* @param startAngle* @param sweepAngle* @param string*/private void drawText(float startAngle, float sweepAngle, String string){Path path = new Path();path.addArc(mRange, startAngle, sweepAngle);float textWidth = mTextPaint.measureText(string);// 利用水平偏移让文字居中float hOffset = (float) (mRadius * Math.PI / mItemCount / 2 - textWidth / 2);// 水平偏移float vOffset = mRadius / 2 / 6;// 垂直偏移mCanvas.drawTextOnPath(string, path, hOffset, vOffset, mTextPaint);}/*** 点击开始旋转* * @param luckyIndex*/public void luckyStart(int luckyIndex){// 每项角度大小float angle = (float) (360 / mItemCount);// 中奖角度范围(因为指针向上,所以水平第一项旋转到指针指向,需要旋转210-270;)float from = 270 - (luckyIndex + 1) * angle;float to = from + angle;// 停下来时旋转的距离float targetFrom = 4 * 360 + from;/*** <pre>*  (v1 + 0) * (v1+1) / 2 = target ;*  v1*v1 + v1 - 2target = 0 ;*  v1=-1+(1*1 + 8 *1 * target)/2;* </pre>*/float v1 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetFrom) - 1) / 2;float targetTo = 4 * 360 + to;float v2 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetTo) - 1) / 2;mSpeed = (float) (v1 + Math.random() * (v2 - v1));isShouldEnd = false;}public void luckyEnd(){mStartAngle = 0;isShouldEnd = true;}public boolean isStart(){return mSpeed != 0;}public boolean isShouldEnd(){return isShouldEnd;}}

代码下载

源代码

参考链接

Android SurfaceView实战 打造抽奖转盘 - Hongyang - 博客频道 - CSDN.NET

实战 flabby bird

效果图

分析

仔细观察游戏,需要绘制的有:背景、地板、鸟、管道、分数;
游戏开始时:
地板给人一种想左移动的感觉;
管道与地板同样的速度向左移动;
鸟默认下落;
当用户touch屏幕时,鸟上升一段距离后,下落;
运动过程中需要判断管道和鸟之间的位置关系,是否触碰,是否穿过等,需要计算分数。

可以分为

  1. piple类
  2. bird类
  3. floor类
  4. Game类

等来实现

GameFlabbyBird类代码

package com.zhy.view;import java.util.ArrayList;
import java.util.List;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;import com.zhy.surfaceViewDemo.R;public class GameFlabbyBird extends SurfaceView implements Callback, Runnable
{private SurfaceHolder mHolder;/*** 与SurfaceHolder绑定的Canvas*/private Canvas mCanvas;/*** 用于绘制的线程*/private Thread t;/*** 线程的控制开关*/private boolean isRunning;private Paint mPaint;/*** 当前View的尺寸*/private int mWidth;private int mHeight;private RectF mGamePanelRect = new RectF();/*** 背景*/private Bitmap mBg;/*** *********鸟相关***********************/private Bird mBird;private Bitmap mBirdBitmap;/*** 地板*/private Floor mFloor;private Bitmap mFloorBg;/*** *********管道相关***********************//*** 管道*/private Bitmap mPipeTop;private Bitmap mPipeBottom;private RectF mPipeRect;private int mPipeWidth;/*** 管道的宽度 60dp*/private static final int PIPE_WIDTH = 60;private List<Pipe> mPipes = new ArrayList<Pipe>();/*** 分数*/private final int[] mNums = new int[] { R.drawable.n0, R.drawable.n1,R.drawable.n2, R.drawable.n3, R.drawable.n4, R.drawable.n5,R.drawable.n6, R.drawable.n7, R.drawable.n8, R.drawable.n9 };private Bitmap[] mNumBitmap;private int mGrade = 0;private int mRemovedPipe = 0;private static final float RADIO_SINGLE_NUM_HEIGHT = 1 / 15f;private int mSingleGradeWidth;private int mSingleGradeHeight;private RectF mSingleNumRectF;private int mSpeed = Util.dp2px(getContext(), 2);/***********************************/private enum GameStatus{WAITTING, RUNNING, STOP;}/*** 记录游戏的状态*/private GameStatus mStatus = GameStatus.WAITTING;/*** 触摸上升的距离,因为是上升,所以为负值*/private static final int TOUCH_UP_SIZE = -16;/*** 将上升的距离转化为px;这里多存储一个变量,变量在run中计算* */private final int mBirdUpDis = Util.dp2px(getContext(), TOUCH_UP_SIZE);private int mTmpBirdDis;/*** 鸟自动下落的距离*/private final int mAutoDownSpeed = Util.dp2px(getContext(), 2);/*** 两个管道间距离*/private final int PIPE_DIS_BETWEEN_TWO = Util.dp2px(getContext(), 300);/*** 记录移动的距离,达到 PIPE_DIS_BETWEEN_TWO 则生成一个管道*/private int mTmpMoveDistance;/*** 记录需要移除的管道*/private List<Pipe> mNeedRemovePipe = new ArrayList<Pipe>();/*** 处理一些逻辑上的计算*/private void logic(){switch (mStatus){case RUNNING:mGrade = 0;// 更新我们地板绘制的x坐标,地板移动mFloor.setX(mFloor.getX() - mSpeed);logicPipe();// 默认下落,点击时瞬间上升mTmpBirdDis += mAutoDownSpeed;mBird.setY(mBird.getY() + mTmpBirdDis);// 计算分数mGrade += mRemovedPipe;for (Pipe pipe : mPipes){if (pipe.getX() + mPipeWidth < mBird.getX()){mGrade++;}}checkGameOver();break;case STOP: // 鸟落下// 如果鸟还在空中,先让它掉下来if (mBird.getY() < mFloor.getY() - mBird.getWidth()){mTmpBirdDis += mAutoDownSpeed;mBird.setY(mBird.getY() + mTmpBirdDis);} else{mStatus = GameStatus.WAITTING;initPos();}break;default:break;}}/*** 重置鸟的位置等数据*/private void initPos(){mPipes.clear();//立即增加一个mPipes.add(new Pipe(getContext(), getWidth(), getHeight(), mPipeTop,mPipeBottom));mNeedRemovePipe.clear();// 重置鸟的位置// mBird.setY(mHeight * 2 / 3);mBird.resetHeigt();// 重置下落速度mTmpBirdDis = 0;mTmpMoveDistance = 0 ;mRemovedPipe = 0;}private void checkGameOver(){// 如果触碰地板,ggif (mBird.getY() > mFloor.getY() - mBird.getHeight()){mStatus = GameStatus.STOP;}// 如果撞到管道for (Pipe wall : mPipes){// 已经穿过的if (wall.getX() + mPipeWidth < mBird.getX()){continue;}if (wall.touchBird(mBird)){mStatus = GameStatus.STOP;break;}}}private void logicPipe(){// 管道移动for (Pipe pipe : mPipes){if (pipe.getX() < -mPipeWidth){mNeedRemovePipe.add(pipe);mRemovedPipe++;continue;}pipe.setX(pipe.getX() - mSpeed);}// 移除管道mPipes.removeAll(mNeedRemovePipe);mNeedRemovePipe.clear();// Log.e("TAG", "现存管道数量:" + mPipes.size());// 管道mTmpMoveDistance += mSpeed;// 生成一个管道if (mTmpMoveDistance >= PIPE_DIS_BETWEEN_TWO){Pipe pipe = new Pipe(getContext(), getWidth(), getHeight(),mPipeTop, mPipeBottom);mPipes.add(pipe);mTmpMoveDistance = 0;}}@Overridepublic boolean onTouchEvent(MotionEvent event){int action = event.getAction();if (action == MotionEvent.ACTION_DOWN){switch (mStatus){case WAITTING:mStatus = GameStatus.RUNNING;break;case RUNNING:mTmpBirdDis = mBirdUpDis;break;}}return true;}public GameFlabbyBird(Context context){this(context, null);}public GameFlabbyBird(Context context, AttributeSet attrs){super(context, attrs);mHolder = getHolder();mHolder.addCallback(this);setZOrderOnTop(true);// 设置画布 背景透明mHolder.setFormat(PixelFormat.TRANSLUCENT);// 设置可获得焦点setFocusable(true);setFocusableInTouchMode(true);// 设置常亮this.setKeepScreenOn(true);mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setDither(true);initBitmaps();// 初始化速度// mSpeed = Util.dp2px(getContext(), 2);mPipeWidth = Util.dp2px(getContext(), PIPE_WIDTH);}/*** 初始化图片*/private void initBitmaps(){mBg = loadImageByResId(R.drawable.bg1);mBirdBitmap = loadImageByResId(R.drawable.b1);mFloorBg = loadImageByResId(R.drawable.floor_bg2);mPipeTop = loadImageByResId(R.drawable.g2);mPipeBottom = loadImageByResId(R.drawable.g1);mNumBitmap = new Bitmap[mNums.length];for (int i = 0; i < mNumBitmap.length; i++){mNumBitmap[i] = loadImageByResId(mNums[i]);}}@Overridepublic void surfaceCreated(SurfaceHolder holder){Log.e("TAG", "surfaceCreated");// 开启线程isRunning = true;t = new Thread(this);t.start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height){Log.e("TAG", "surfaceChanged");// TODO Auto-generated method stub}@Overridepublic void surfaceDestroyed(SurfaceHolder holder){Log.e("TAG", "surfaceDestroyed");// 通知关闭线程isRunning = false;}@Overridepublic void run(){while (isRunning){long start = System.currentTimeMillis();logic();draw();long end = System.currentTimeMillis();try{if (end - start < 50){Thread.sleep(50 - (end - start));}} catch (InterruptedException e){e.printStackTrace();}}}private void draw(){try{// 获得canvasmCanvas = mHolder.lockCanvas();if (mCanvas != null){// drawSomething..drawBg();drawBird();drawPipes();drawFloor();drawGrades();}} catch (Exception e){} finally{if (mCanvas != null)mHolder.unlockCanvasAndPost(mCanvas);}}private void drawFloor(){mFloor.draw(mCanvas, mPaint);}/*** 绘制背景*/private void drawBg(){mCanvas.drawBitmap(mBg, null, mGamePanelRect, null);}private void drawBird(){mBird.draw(mCanvas);}/*** 绘制管道*/private void drawPipes(){for (Pipe pipe : mPipes){// pipe.setX(pipe.getX() - mSpeed);pipe.draw(mCanvas, mPipeRect);}}/*** 初始化尺寸相关*/@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh){super.onSizeChanged(w, h, oldw, oldh);mWidth = w;mHeight = h;mGamePanelRect.set(0, 0, w, h);// 初始化mBirdmBird = new Bird(getContext(), mWidth, mHeight, mBirdBitmap);// 初始化地板mFloor = new Floor(mWidth, mHeight, mFloorBg);// 初始化管道范围mPipeRect = new RectF(0, 0, mPipeWidth, mHeight);Pipe pipe = new Pipe(getContext(), w, h, mPipeTop, mPipeBottom);mPipes.add(pipe);// 初始化分数mSingleGradeHeight = (int) (h * RADIO_SINGLE_NUM_HEIGHT);mSingleGradeWidth = (int) (mSingleGradeHeight * 1.0f/ mNumBitmap[0].getHeight() * mNumBitmap[0].getWidth());mSingleNumRectF = new RectF(0, 0, mSingleGradeWidth, mSingleGradeHeight);}/*** 绘制分数*/private void drawGrades(){String grade = mGrade + "";mCanvas.save(Canvas.MATRIX_SAVE_FLAG);mCanvas.translate(mWidth / 2 - grade.length() * mSingleGradeWidth / 2,1f / 8 * mHeight);// draw single num one by onefor (int i = 0; i < grade.length(); i++){String numStr = grade.substring(i, i + 1);int num = Integer.valueOf(numStr);mCanvas.drawBitmap(mNumBitmap[num], null, mSingleNumRectF, null);mCanvas.translate(mSingleGradeWidth, 0);}mCanvas.restore();}/*** 根据resId加载图片* * @param resId* @return*/private Bitmap loadImageByResId(int resId){return BitmapFactory.decodeResource(getResources(), resId);}
}

MainActivity代码

package com.zhy.surfaceViewDemo;import com.zhy.view.GameFlabbyBird;import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;public class MainActivity extends Activity
{GameFlabbyBird mGame;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);requestWindowFeature(Window.FEATURE_NO_TITLE);mGame = new GameFlabbyBird(this);setContentView(mGame);}}

代码下载

代码下载

参考链接

Android SurfaceView实战 带你玩转flabby bird (上) - Hongyang - 博客频道 - CSDN.NET

Android SurfaceView实战 带你玩转flabby bird (下) - Hongyang - 博客频道 - CSDN.NET

转载于:https://www.cnblogs.com/jjx2013/p/6223641.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/490676.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

日韩决裂,半导体谁最受伤?

来源&#xff1a; 半导体行业观察日本政府于7月1日公布&#xff0c;要加强对韩国的出口管理&#xff0c;7月4日发起了“氟化聚酰亚胺&#xff08;Polymide&#xff09;”、“EUV Resist&#xff08;光阻剂&#xff09;”、“氟化氢”三种半导体材料的出口限制。根据此次出口限制…

验证码随机生成

验证码随机生成 这里主要使用到的库是captcha库&#xff0c;下载的命令如下&#xff1a; pip install captcha 验证码随机生成代码&#xff0c;(python 版本&#xff1a;3.6 captcha 版本&#xff1a;0.3) from captcha.image import ImageCaptcha import numpy as np …

台式电脑麦克风_还有人买台式PC吗?这份新品推荐攻略值得收藏

【科技犬】新品一&#xff0c;联想发布新款天逸510S台式机联想现已推出天逸 510S 小型主机&#xff0c;搭载了英特尔最新的十代酷睿处理器 i5-10400&#xff0c;8GB 内存 512GB SSD 售价 3499 元。联想新款天逸 510S 将于 7 月 23 日开卖&#xff0c;适合企业办公用户使用。天…

天基物联,毫瓦服务,商业航天撬动万亿市场

来源&#xff1a; 卫星与网络2019年8月17日12时11分&#xff0c;酒泉卫星发射中心&#xff0c;北京国电高科科技有限公司&#xff08;以下简称“国电高科”&#xff09;研制的天启沧州号&#xff08;又名“忻中一号”&#xff09;卫星由首次发射的捷龙一号商业火箭成功送入太空…

GitHub如何上传超过100MB的文件

GitHub如何上传超过100MB的文件 平时在GitHub上上传项目文件时&#xff0c;遇到比较大的文件&#xff0c;就会出现无法上传的情况&#xff1a; this exceeds GitHubs file size limit of 100.00 MB 解决方法如下&#xff1a; 在所要上传文件的目录下打开Git 首先&#xff0c;…

人的智商到底有多高?

图片来源&#xff1a;verywell.com来源&#xff1a;生物谷人的智商到底有多高&#xff1f;来自慕尼黑大学的Markus Buhner教授表示&#xff0c;其实日常生活中我们认为的很多事实实际上或许都是误解&#xff0c;这里&#xff0c;研究人员对8种陈词滥调的有效性证据进行了权衡分…

解决问题:Couldn't open file: data/coco.names

错误&#xff1a;Couldn’t open file: data/coco.names darknet GitHub&#xff1a;https://github.com/pjreddie/darknet YOLO官网&#xff1a;https://pjreddie.com/darknet/yolo/ 在进行yolo效果测试时&#xff0c;出现了该错误。通过如下命令下载darknet&#xff1a; git…

linux系统下codeblocks控制台打印中文乱码

linux系统下codeblocks控制台打印中文乱码 在linux下安装codeblocks后&#xff0c;打印中文出现如下问题&#xff1a; #include <stdio.h> #include <stdlib.h>int main() {printf("你好&#xff0c;世界&#xff01;\n");return 0; } 解决办法 1、将…

db2时间格式化为时间到时分秒_快捷指令为 iPhone 手机照片添加时间水印

安卓手机用户&#xff0c;自带的相机一般都有花样繁多的水印功能&#xff0c;可以将当前使用的手机型号、日期时间、品牌等信息以水印形式添加到照片。而苹果手机自带的相机应用可设置的功能较少&#xff0c;不过&#xff0c;苹果系统自带的“快捷指令”应用扩展功能非常强&…

深度学习仍是视觉大数据领域的最好分析方法之一

在这个数据为王的时代&#xff0c;深度学习擅于发掘多维数据中错综复杂的关系。基于大数据的深度学习算法在计算机视觉、自然语言处理以及信息检索等多个领域不断刷新着记录。来源&#xff1a; AI科技评论AI 科技评论注&#xff1a;本文作者为中国科学院信息工程研究所张晓宇副…

matplotlib调节colorbar的大小

调节plt.colorbar的fraction系数即可调节colorbar的大小 weight np.random.random([8, 8]) plt.imshow(weight) plt.colorbar(fraction0.05, pad0.05) plt.savefig(tjn.png, bbox_inchestight) plt.show()

学习opencv 英文版_B站上适合程序员的学习资源【赶紧收藏!】

“二次元&#xff0c;鬼畜&#xff0c;动漫”是大家提到B站&#xff0c;最容易冒出来的关键词&#xff01;然而央视网一条微博却表示&#xff1a;过去一年有近2000万人在B站学习&#xff0c;相当于去年高考人数的2倍&#xff01;B站正在成为年轻人学习的首要阵地。下面整理一些…

Matlab读取json文件

Matlab读取json文件 在matlab中&#xff0c;可以将数据写入json文件&#xff0c;却没发现读取json的函数&#xff0c;网上查了一下&#xff0c;大部分是个人写的函数&#xff0c;再可执行性上可能会有一些问题。最终&#xff0c;还是发现了一个matlab解析json文件的工具包&…

追问人工智能

来源&#xff1a;人机与认知实验室前段时间&#xff0c;英国公司登记处的一份文件披露了 DeepMind 2018 年的财务状况&#xff1a;这家 AI 科技公司的净亏损由 2017 年的 3.41 亿美元增加至 2018 年的 5.72 亿美元&#xff0c;今年到期的债务高达 12.656 亿美元。如此巨额的亏损…

安卓系统挂载NTFS格式硬盘_苹果电脑挥之不去的烦恼!怎样兼容NTFS格式的U盘移动硬盘?...

[PConline 应i用]很多用苹果电脑的朋友&#xff0c;都经常会遇到这样的烦恼&#xff1a;插入某个U盘或者移动硬盘&#xff0c;发现只能读取文件&#xff0c;没法把文件复制进去&#xff01;这是因为这个U盘或者移动硬盘&#xff0c;使用的是NTFS格式&#xff0c;这也是Windows御…

dubbo工作原理

part -- 外挂1.dubbo借助spring的schema启动和初始化 1.1 spring扫描所有jar下META-INF的spring.handlers和spring.schemas。 1.2 运行spring.handlers下定义的DubboNamespaceHandler的init方法。 1.3 spring加载xml&#xff0c;执行DubboBeanDefinitionParser的parse方法&…

问题:AttributeError: 'Tensor' object has no attribute 'creator'

AttributeError: Tensor object has no attribute creator 根据pytorch官方文档的说法&#xff0c;变量具有如上的三个属性&#xff0c;在获取y操作的creator属性时&#xff0c;却出现没有该属性的错误。 import torch from torch.autograd import Variable x Variable(torch…

ACL 2019年度回顾:自然语言处理发展趋势

大数据文摘出品来源&#xff1a;mihaileric编译&#xff1a;赵伟、邢畅、张秋玥今年7月底&#xff0c;计算语言学协会年会&#xff08;ACL&#xff09;在风景优美的佛罗伦萨召开。会场设在了一座古老的Medici家族的城堡中。作为NLP研究最大规模的会议之一&#xff0c;ACL 2019的…

Python基础:获取迭代器下一项目的常见操作

目录 获取迭代器下一项目通常有三种方法 python3中最常见的一种错误使用 获取迭代器下一项目通常有三种方法 next()函数iterator.__next__()属性for循环 next()函数 iterator iter([1,2,3,4,5,6]) a next(iterator) print(a) b next(iterator) print(b) 输出&#xff1…

电商项目的并发量一般是多少_掌握这些,高并发秒杀系统就不用担心了!

很多小伙伴反馈说&#xff0c;高并发专题学了那么久&#xff0c;但是&#xff0c;在真正做项目时&#xff0c;仍然不知道如何下手处理高并发业务场景!图片来自 Pexels甚至很多小伙伴仍然停留在只是简单的提供接口(CRUD)阶段&#xff0c;不知道学习的并发知识如何运用到实际项目…