屏幕和绘图

  • 屏幕
    • 系统屏幕密度
    • 独立像素密度dp
    • 单位转换
  • XML绘图(需放在Drawable)
    • Bitmap
    • Shape
    • Layer
    • Selector
  • 绘图技巧
    • Canvas
    • Layer
    • PorterDuffXfermode
    • Shader
    • PathEffect
    • SurfaceView

屏幕

  • 屏幕大小:指屏幕对角线长度,单位为寸
  • 分辨率:指屏幕宽高的像素点个数,如720x1280
  • PPI:每英寸像素(Pixels Per Inch),指对角线的像素点数除以屏幕大小,又称屏幕密度DPI(Dots Per Inch)

系统屏幕密度

不同手机的大小和像素密度都不同,为统一,定义了几个标准的DPI值

独立像素密度dp

相同的像素,在不同密度的屏幕上显示,长度会不同,因为高密度的屏幕包含更多像素点

  • 规定密度为mdpi(即密度值为160)时1px=1dp
  • 故上图各分辨率的换算比例为3:4:6:8:12

单位转换

如下工具类提供了px、dp、sp的互相转换

public class DisplayUtil {// dp = 像素/密度public static int px2dip(Context context, float pxValue) {float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5f);}public static int dip2px(Context context, float dipValue) {float scale = context.getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}// sp = 像素/缩放密度public static int px2sp(Context context, float pxValue) {float fontScale = context.getResources().getDisplayMetrics().scaledDensity;return (int) (pxValue / fontScale + 0.5f);}public static int sp2px(Context context, float spValue) {float fontScale = context.getResources().getDisplayMetrics().scaledDensity;return (int) (spValue * fontScale + 0.5f);}
}

或可以使用TypedValue.applyDimension()方法

public int dp2px(int dp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics());
}public int sp2px(int sp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());
}

XML绘图(需放在Drawable)

Bitmap

如下引用图片并转为Bitmap

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"android:src="@mipmap/ic_launcher" />

Shape

Shape可实现不同类型的形状,如下实现渐变阴影

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><gradientandroid:angle="45"android:endColor="#805FBBFF"android:startColor="#FF5DA2FF" /><paddingandroid:bottom="7dp"android:left="7dp"android:right="7dp"android:top="7dp" /><corners android:radius="8dp" />
</shape>

效果如图

Layer

Layer可实现类似PS中图层的概念

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@mipmap/ic_launcher" /><itemandroid:bottom="50dp"android:drawable="@mipmap/ic_launcher"android:left="50dp"android:right="50dp"android:top="50dp" />
</layer-list>

上面两个item分别为图片进行叠加,效果如图

Selector

Selector实现不同事件设置反馈,如下实现修改为圆角矩形,点击后切换颜色

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_pressed="true"><shape android:shape="rectangle"><solid android:color="#33444444" /><corners android:radius="5dp" /><padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" /></shape></item><item><shape android:shape="rectangle"><solid android:color="#FFFFFF" /><corners android:radius="5dp" /><padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" /></shape></item>
</selector>

绘图技巧

Canvas

下面为常用的方法

  • save():将已绘制图像保存,在此之后的操作绘制在新图层
  • restore():合并图层,将save()之后绘制的图像和save()之前的合并
  • translate():坐标系平移
  • ratate():坐标系旋转

如下绘制一个时钟,通过平移、旋转坐标系简化实现

public class Clock extends View {private int mWidth;private int mHeight;public Clock(Context context) {super(context);}public Clock(Context context, AttributeSet attrs) {super(context, attrs);}public Clock(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = getMeasuredWidth();mHeight = getMeasuredHeight();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 绘制外圆,以(mWidth / 2, mHeight / 2)为圆形,以mWidth / 2为半径Paint paintCircle = new Paint();paintCircle.setStyle(Paint.Style.STROKE);paintCircle.setAntiAlias(true);paintCircle.setStrokeWidth(5);canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, paintCircle);// 绘制刻度Paint paintDegree = new Paint();for (int i = 0; i < 24; i++) {if (i == 0 || i == 6 || i == 12 || i == 18) {paintDegree.setStrokeWidth(5);paintDegree.setTextSize(30);canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,mWidth / 2, mHeight / 2 - mWidth / 2 + 60,paintDegree);String degree = String.valueOf(i);canvas.drawText(degree,mWidth / 2 - paintDegree.measureText(degree) / 2,mHeight / 2 - mWidth / 2 + 90,paintDegree);} else {paintDegree.setStrokeWidth(3);paintDegree.setTextSize(15);canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,mWidth / 2, mHeight / 2 - mWidth / 2 + 30,paintDegree);String degree = String.valueOf(i);canvas.drawText(degree,mWidth / 2 - paintDegree.measureText(degree) / 2,mHeight / 2 - mWidth / 2 + 60,paintDegree);}// 将画布以圆心旋转15°,简化坐标运算canvas.rotate(15, mWidth / 2, mHeight / 2);}// 绘制指针Paint paintHour = new Paint();paintHour.setStrokeWidth(20);Paint paintMinute = new Paint();paintMinute.setStrokeWidth(10);canvas.save();canvas.translate(mWidth / 2, mHeight / 2); // 将坐标系平移到圆点,再画指针canvas.drawLine(0, 0, 100, 100, paintHour);canvas.drawLine(0, 0, 100, 200, paintMinute);canvas.restore();}
}

Layer

图层基于栈结构,入栈后操作都发生在该图层上,出栈后则把图像绘制到上层Canvas

  • 入栈:saveLayer()、saveLayerAlpha()
  • 出栈:restore()、restoreToCount()
public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Paint mPaint;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mPaint = new Paint();}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawColor(Color.WHITE);mPaint.setColor(Color.BLUE);canvas.drawCircle(150, 150, 100, mPaint);canvas.saveLayerAlpha(0, 0, 400, 400, 127);mPaint.setColor(Color.RED);canvas.drawCircle(200, 200, 100, mPaint);canvas.restore();}
}

如下图,透明度为127的红色圆叠加在蓝色圆上方

PorterDuffXfermode

PorterDuffXfermod设置的是两个图层交集区域的显示方式,dst是先画的图形,而src是后画的图形,共有16种模式,如图

如下实现圆角图形,mOut为先画的图像,mBitmap为后画的图像,用SrcIn取交集

public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Bitmap mBitmap;private Bitmap mOut;private Paint mPaint;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);mOut = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(mOut);mPaint = new Paint();mPaint.setAntiAlias(true);canvas.drawRoundRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(), 80, 80, mPaint);mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));canvas.drawBitmap(mBitmap, 0, 0, mPaint);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawBitmap(mOut, 0, 0, null);}
}

效果如图

如下代码设置透明的画笔,实时获取坐标调用drawPath()涂抹上面的图层,实现刮刮乐

public class XfermodeView extends View {private Bitmap mBgBitmap, mFgBitmap;private Paint mPaint;private Canvas mCanvas;private Path mPath;public XfermodeView(Context context) {this(context, null);}public XfermodeView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mPaint = new Paint();mPaint.setAlpha(0);mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeJoin(Paint.Join.ROUND);mPaint.setStrokeWidth(50);mPaint.setStrokeCap(Paint.Cap.ROUND);mPath = new Path();mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.b);mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(), mBgBitmap.getHeight(), Bitmap.Config.ARGB_8888);mCanvas = new Canvas(mFgBitmap);mCanvas.drawColor(Color.GRAY);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mPath.reset();mPath.moveTo(event.getX(), event.getY());break;case MotionEvent.ACTION_MOVE:mPath.lineTo(event.getX(), event.getY());break;}mCanvas.drawPath(mPath, mPaint);invalidate();return true;}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawBitmap(mBgBitmap, 0, 0, null);canvas.drawBitmap(mFgBitmap, 0, 0, null);}
}

Shader

用于实现渐变、渲染效果,包括

  • BitmapShader——位图Shader
  • LinnerGradient——线性Shader
  • RadialGradient——光束Shader
  • SweepGradient——梯度Shader
  • ComposeShader——混合Shader

上述渐变都有三种模式选择:

  • CLAMP:拉伸,拉伸的是图片最后一个像素,不断重复
  • REPEAT:重复,横向、纵向不断重复
  • MIRROR:镜像,横向、纵向不断翻转重复

如下,将图片填充到BitmapShader,创建一支具有图像填充功能的Paint

public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Bitmap mBitmap;private Paint mPaint;private BitmapShader mBitmapShader;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);mPaint = new Paint();mPaint.setShader(mBitmapShader);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawCircle(mBitmap.getWidth() / 2.0f, mBitmap.getHeight() / 2.0f, 50, mPaint);}
}

利用Paint在图片中心绘制圆形,效果如下


如下改为REPEAT,并扩大半径,可看到图片不断重复绘制

public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Bitmap mBitmap;private Paint mPaint;private BitmapShader mBitmapShader;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);mPaint = new Paint();mPaint.setShader(mBitmapShader);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawCircle(mBitmap.getWidth() / 2.0f, mBitmap.getHeight() / 2.0f, 500, mPaint);}
}

如下利用PorterDuffXfermode和LinnerGradient实现倒影效果的图片

public class ReflectView extends View {private Bitmap mSrcBitmap, mRefBitmap;private Paint mPaint;private PorterDuffXfermode mXfermode;public ReflectView(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init() {mSrcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.b);Matrix matrix = new Matrix();matrix.setScale(1F, -1F);//垂直翻转mRefBitmap = Bitmap.createBitmap(mSrcBitmap, 0, 0,mSrcBitmap.getWidth(), mSrcBitmap.getHeight(), matrix, true);mPaint = new Paint();mPaint.setShader(new LinearGradient(0, mSrcBitmap.getHeight(),0, mSrcBitmap.getHeight() * 2,0xDD000000, 0x10000000, Shader.TileMode.REPEAT));mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.BLACK);//原图canvas.drawBitmap(mSrcBitmap, 0, 0, null);//倒影图canvas.drawBitmap(mRefBitmap, 0, mSrcBitmap.getHeight(), null);mPaint.setXfermode(mXfermode);//绘制渐变效果层canvas.drawRect(0, mRefBitmap.getHeight(), mRefBitmap.getWidth(), mSrcBitmap.getHeight() * 2, mPaint);mPaint.setXfermode(null);}
}

先将图片翻转,再添加黑色透明度递减的渐变,DST_IN是为了避免上面的图像被渐变效果遮挡

PathEffect

PathEffect指用各种笔触效果来绘制一个路径

如上,分别为

  • 无效果
  • CornerPathEffect:线段拐角圆滑
  • DiscretePathEffect:线段出现杂点
  • DashPathEffect:绘制虚线,用一个数组来设置各个点之间的间隔,还可设置偏移量实现动态路径效果
  • PathPathEffect:类似DashPathEffect,但还可设置点的图形,如上面的圆点虚线
  • ConposePathEffect:组合效果
public class MyView extends View {private static final String TAG = MyView.class.getSimpleName();private Path mPath;private PathEffect[] mPathEffect;private Paint mPaint;public MyView(Context context) {this(context, null);}public MyView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyView(Context context, AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);mPaint = new Paint();mPaint.setStyle(Paint.Style.STROKE);mPath = new Path();mPath.moveTo(0, 0);for (int i = 0; i <= 30; i++) {mPath.lineTo(i * 35, (float) (Math.random() * 100));}mPathEffect = new PathEffect[6];mPathEffect[0] = null;mPathEffect[1] = new CornerPathEffect(30);mPathEffect[2] = new DiscretePathEffect(3.0F, 5.0F);mPathEffect[3] = new DashPathEffect(new float[]{20, 10, 5, 10}, 0);Path path = new Path();path.addRect(0, 0, 8, 8, Path.Direction.CCW);mPathEffect[4] = new PathDashPathEffect(path, 12, 0, PathDashPathEffect.Style.ROTATE);mPathEffect[5] = new ComposePathEffect(mPathEffect[3], mPathEffect[1]);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (PathEffect pathEffect : mPathEffect) {mPaint.setPathEffect(pathEffect);canvas.drawPath(mPath, mPaint);canvas.translate(0, 200);}}
}

SurfaceView

Android通过VSYNC信号刷新View进行屏幕的重绘,时间间隔为16ms,若在需要频繁刷新的界面上执行太多的操作逻辑,则容易阻塞主线程,造成画面卡顿

当需要频繁刷新或刷新时数据处理量比较大时,可使用SurfaceView

  • View用于主动刷新,SurfaceView用于被动刷新
  • View在主线程刷新,SurfaceView在子线程刷新
  • View绘图未使用双缓冲机制,SurfaceView则使用双缓冲机制

SurfaceView的模板代码如下,主要原理是初始化时自行创建子线程并调用draw()方法绘制

public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable {//内部Holder,用于获取Canvas和提交绘制private SurfaceHolder mHolder;//用于控制线程的标志位private boolean mIsDrawing;//用于绘图的Canvasprivate Canvas mCanvas;public SurfaceViewTemplate(Context context) {this(context, null);}public SurfaceViewTemplate(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mHolder = getHolder();mHolder.addCallback(this);  //将自身作为回调setFocusableInTouchMode(true);setFocusable(true);this.setKeepScreenOn(true);}//创建时开启线程,调用draw()@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;new Thread(this).start();}//改变时回调@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}//结束时回调@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsDrawing = false;}@Overridepublic void run() {while (mIsDrawing) {draw();}}private void draw() {try {mCanvas = mHolder.lockCanvas();//获取Canvas开始绘制,获取的并非新的Canvas,而是上次的} catch (Exception e) {e.printStackTrace();} finally {if (mHolder != null) {//绘制完后需提交mHolder.unlockCanvasAndPost(mCanvas);}}}
}

如下代码利用SurfaceView实现正弦函数的动态绘制

public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable {private SurfaceHolder mHolder;private boolean mIsDrawing;private Canvas mCanvas;private int x;private int y;private Path mPath;private Paint mPaint;public SurfaceViewTemplate(Context context) {this(context, null);}public SurfaceViewTemplate(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mPath = new Path();mPaint = new Paint();mPaint.setStyle(Paint.Style.STROKE);mHolder = getHolder();mHolder.addCallback(this);setFocusableInTouchMode(true);setFocusable(true);this.setKeepScreenOn(true);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;new Thread(this).start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsDrawing = false;}@Overridepublic void run() {while (mIsDrawing) {draw();x += 1;y = (int) (100 * Math.sin(x * 2 * Math.PI / 180) + 400);mPath.lineTo(x, y);}}private void draw() {try {mCanvas = mHolder.lockCanvas();mCanvas.drawColor(Color.WHITE); //设置背景mCanvas.drawPath(mPath, mPaint);} catch (Exception e) {e.printStackTrace();} finally {if (mHolder != null) {mHolder.unlockCanvasAndPost(mCanvas);}}}
}

效果如图

如下代码利用SurfaceView实现绘图板,根据手指移动绘制路径,在draw()中调用sleep()避免过度频繁绘制

public class SurfaceViewTemplate extends SurfaceView implements SurfaceHolder.Callback, Runnable {private SurfaceHolder mHolder;private boolean mIsDrawing;private Canvas mCanvas;private Path mPath;private Paint mPaint;public SurfaceViewTemplate(Context context) {this(context, null);}public SurfaceViewTemplate(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mPath = new Path();mPaint = new Paint();mPaint.setStyle(Paint.Style.STROKE);mHolder = getHolder();mHolder.addCallback(this);setFocusableInTouchMode(true);setFocusable(true);this.setKeepScreenOn(true);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;new Thread(this).start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsDrawing = false;}@Overridepublic boolean onTouchEvent(MotionEvent event) {int x = (int) event.getX();int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mPath.moveTo(x, y);break;case MotionEvent.ACTION_MOVE:mPath.lineTo(x, y);break;case MotionEvent.ACTION_UP:break;}return true;}@Overridepublic void run() {long start = System.currentTimeMillis();while (mIsDrawing) {draw();}long end = System.currentTimeMillis();if (end - start < 100) {SystemClock.sleep(100 - (end - start));}}private void draw() {try {mCanvas = mHolder.lockCanvas();mCanvas.drawColor(Color.WHITE);mCanvas.drawPath(mPath, mPaint);} catch (Exception e) {e.printStackTrace();} finally {if (mHolder != null) {mHolder.unlockCanvasAndPost(mCanvas);}}}
}

效果如图

Android中级——屏幕和绘图相关推荐

  1. Android中级篇之百度地图SDK v3.5.0-一步一步带你仿各大主流APP地图定位移动选址功能

    from: http://blog.csdn.net/y1scp/article/details/49095729 定位+移动选址 百学须先立志-学前须知: 我们经常在各大主流APP上要求被写上地址, ...

  2. android不同屏幕分辨率的适配

    2019独角兽企业重金招聘Python工程师标准>>> 有必要了解的 Android中常见的单位 dip, dp, px, sp之间的区别: dip: device independ ...

  3. android 多屏幕适配 : 第一部分

    1.在xml布局文件中,控件的宽度和高度用  dp ;   字体大小用 sp 2.根据屏幕的宽高来动态的适配 , 获取屏幕的宽高的两种方法: 第一种方法: /*** 屏幕的宽度* 屏幕的高度* @re ...

  4. Android应用屏幕适应问题的解决

    2019独角兽企业重金招聘Python工程师标准>>> 1.android多屏幕支持机制  Android的支持多屏幕机制即用为当前设备屏幕提供一种合适的方式来共同管理并解析应用资源 ...

  5. Android自适应屏幕大小和布局

    一:不同的layout  Android手机屏幕大小不一,有480x320, 640x360, 800x480,854x480.怎样才能让App自动适应不同的屏幕呢? 其实很简单,只需要在res目录下 ...

  6. android多屏幕适配资源生成,android – 多屏幕适配相关

    1.基本概念 屏幕大小(screen size) – 屏幕的实际大小,用屏幕对角线长度来衡量(比如3.4寸,3.8寸).android把屏幕分为以下4种:small,normal,large,extr ...

  7. android 多屏幕 设计翻译,android Supporting multiple screen翻译一

    Multiple screens quickview:多个屏幕quickview: ·Android runs on devices that have different screen sizes ...

  8. 154在屏幕中绘图时设置透明度(扩展知识:为图片视图添加点击手势识别器,来实现点击事件操作)...

    一张图片,通过混合模式绘制后,能得到不同效果的图片. 这里的示例仅是测试效果:实际上可以通过不同程度的混合模式绘制,来得到符合需求的效果. 效果如下: ViewController.h 1 #impo ...

  9. android 获取屏幕的宽高

    今天,讲讲android如何获取屏幕的宽高. // 通过WindowManager获取 DisplayMetrics dm = new DisplayMetrics(); getWindowManag ...

最新文章

  1. mysql定制rpm包_mysql运维管理-企业rpm包的定制
  2. keras cnn注意力机制_TensorFlow、PyTorch、Keras:NLP框架哪家强
  3. ThreadLocal的第二种用法 part2
  4. 如何使用ABAP把数字转换成单词
  5. 奇妙的安全旅行之加密算法(完整版)
  6. svm回归matlab工具箱很慢,PSO优化SVM参数进行回归预测,结果很不理想
  7. sublime text3占用CPU过高
  8. 极客大学架构师训练营 - 同城快递业务架构设计 - 大作业一
  9. JDE 系统表(标准表)
  10. 官方免费申请许可证-VMware Fusion 12 – Personal Use License
  11. 阿里java电话面试题
  12. 一款非常萌的桌面工具---bongo cat mver0.1.6 附使用教程
  13. Redis设计与实现(一)| 数据结构 对象
  14. lzg_ad:XPE镜像文件部署详解
  15. 灵隐寺高僧汇报 “数字化寺院” 方案,走红网络! “系统可用性” 随缘、KPI 随心?...
  16. Jarvis OJ BASIC 公倍数
  17. 签约新闻 | 出版发行行业又一位老牌企业的数字化转型,扬帆起航!
  18. 163邮箱如何登录,在哪可以登录邮箱?
  19. Week15—字典树应用,字符串包含问题
  20. Licode架构分析

热门文章

  1. 从青铜到王者,进阶数据可视化2.0的五个Python库
  2. 无线WIFI网络密码破解程序
  3. 人体十大最佳黄金时间
  4. python 阶乘算法
  5. 如今是云散雪消花残月缺
  6. drupal安装配置错误
  7. 知识图谱之实体对齐一
  8. 斗仙服务器维护礼包,《斗仙》2.730版本更新公告(测试区 2017.6.26)
  9. 刷脸支付代理加盟需要注意哪些事项
  10. 生产者-消费者模式分析