Android查缺补漏(View篇)–自定义 View 的着力流程

by admin on 2018年10月25日

MotionEvent 触摸事件

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.i(TAG, "onTouchEvent: ACTION_DOWN");
            break;
        case MotionEvent.ACTION_UP:
            Log.i(TAG, "onTouchEvent: ACTION_UP");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.i(TAG, "onTouchEvent: ACTION_MOVE");
            break;
    }
    return super.onTouchEvent(event);
}

于由定义 View 中,重写 onTouchEvent() 方法,获取
MotionEvent,正而上面代码所勾画,MotionEvent 比较常用之轩然大波有三种
ACTION_DOWN、ACTION_MOVE、ACTION_UP 分别指向承诺指按下-移动-离开。

联网下对端的周demo添加一个小事件,就是在手指点击一下屏幕,圆形就擅自换一种颜色:

private Random mRandom = new Random(100);
private int[] mColors = new int[] {
  Color.parseColor("#ff0000"),
  Color.parseColor("#ffffff"),
  Color.parseColor("#ff00ff"),
  Color.parseColor("#ffff00"),
  Color.parseColor("#ff00ff"),
  Color.parseColor("#0000ff")
};

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mColor = mColors[mRandom.nextInt(6)];
            mPaint.setColor(mColor);
            invalidate(); // 通知控件重绘
            break;
        case MotionEvent.ACTION_UP:
            Log.i(TAG, "onTouchEvent: ACTION_UP");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.i(TAG, "onTouchEvent: ACTION_MOVE");
            break;
    }
    return super.onTouchEvent(event);
}

效益如下:
图片 1

大家为足以当这个基础及稍微再推而广之一下,例如:通过 event.getX() 和
event.getY()
获取触摸点的坐标,判断出点是否收获于了环区域外,从而使只发硌手指点到环区域外才改变颜色,否则不转移。感兴趣的童鞋可机关动手试一试行。

每当点代码中通报 View 重绘时使用了 invalidate() 方法,其实
postInvalidate() 也得以通 View 重绘,那么就有限啊生出什么界别吧?

其实简单的话,invalidate() 只会于 UI 线程中行使,而 postInvalidate()
可以当子线程中动用。

二、DIB的结构

  在 Windows 3.0
以前,Windows系统用之凡DDB(设备有关各图)。DDB没有调色板,显示的水彩依赖硬件,处理色彩非常不便利。所以
Microsoft 在 Windows 3.0中 重新定义了BMP文件格式(BMP
3.0),使其支持设备无关位图——也就算是DIB。

 

  时至今日,BMP的版本号已腾到5.0(Windows NT 4.0、Windows95 定义了 BMP
4.0,Windows 98、Windows 2000 定义了 BMP 5.0),但基本组织没有更换——仍是
BMP文件头 和 DIB 组成:

 

BMP文件

 

BITMAPFILEHEADER

BMP文件头

DIB

BITMAPINFOHEADER

员图信息头

BITMAPINFO

RGBQUAD[]

调色板

 

位图数据

(#意味着可以不填(=0)的品类)

BMP文件头——BITMAPFILEHEADER

原型定义:

typedef struct tagBITMAPFILEHEADER { // bmfh
    WORD    bfType;
    DWORD   bfSize;
    WORD    bfReserved1;
    WORD    bfReserved2;
    DWORD   bfOffBits;
} BITMAPFILEHEADER;

VB声明:

Type BITMAPFILEHEADER
    bfType(0 to 1) As Byte
    bfSize As Long
    bfReserved1 As Integer
    bfReserved2 As Integer
    bfOffBits As Long
End Type

说明:

bfType

指令文件的门类,必须是“BM”

bfSize#

指令文件之分寸,包括BITMAPFILEHEADER

bfReserved1

保留,=0

bfReserved2

保留,=0

bfOffBits#

从今文本头至位图数据的偏移字节数

文件信息头——BITMAPINFOHEADER

原型定义:

typedef struct tagBITMAPINFOHEADER{ // bmih
    DWORD  biSize;
    LONG   biWidth;
    LONG   biHeight;
    WORD   biPlanes;
    WORD   biBitCount;
    DWORD  biCompression;
    DWORD  biSizeImage;
    LONG   biXPelsPerMeter;
    LONG   biYPelsPerMeter;
    DWORD  biClrUsed;
    DWORD  biClrImportant;
} BITMAPINFOHEADER;

VB声明:

Type BITMAPINFOHEADER
    biSize As Long
    biWidth As Long
    biHeight As Long
    biPlanes As Integer
    biBitCount As Integer
    biCompression As Long
    biSizeImage As Long
    biXPelsPerMeter As Long
    biYPelsPerMeter As Long
    biClrUsed As Long
    biClrImportant As Long
End Type

说明:

biSize

BITMAPINFOHEADER结构的高低。BMP有差不多只版本,就靠biSize来分别:
  BMP3.0:BITMAPINFOHEADER(=40)
  BMP4.0:BITMAPV4HEADER(=108)
  BMP5.0:BITMAPV5HEADER(=124)

biWidth

位图的冲天,单位是比如说从

biHeight

位图的宽,单位凡诸如从

biPlanes

配备的号平面数。现在犹是1

biBitCount

图像的水彩位数
   0:当biCompression=BI_JPEG时要为0(BMP 5.0)
   1:单色位图
   4:16色位图
   8:256色位图
  16:增强色位图,默认为555格式
  24:真彩色位图
  32:32个位图,默认情况下Windows不见面处理高8位,可以用她作为友好的Alpha通道

biCompression

调减方式
  BI_RGB:无压缩
  BI_RLE8:行程编码压缩,biBitCount必须顶被8
  BI_RLE4:行程编码压缩,biBitCount必须等于4
  BI_BITFIELDS:指定RGB掩码,biBitCount必须等16、32
  BI_JPEG:JPEG压缩(BMP 5.0)
  BI_PNG:PNG压缩(BMP 5.0)

biSizeImage#

其实的位图数据所占有字节(biCompression=BI_RGB时可以简简单单)

biXPelsPerMeter#

对象设备的品位分辨率,单位是各个米之像素个数

biYPelsPerMeter#

靶设备的直分辨率,单位是每米之像素个数

biClrUsed#

以的颜色数(当biBitCount等深受1、4、8时才使得)。如果该项为0,表示颜色数为2^biBitCount

biClrImportant#

关键的颜色数。如果该项为0,表示有颜色都是必不可缺之

调色板
  只有biBitCount等深受1、4、8时才发生调色板。调色板实际上是一个屡屡组,元素的个数由biBitCount和biClrUsed决定。

原型定义:

typedef struct tagRGBQUAD { // rgbq
    BYTE    rgbBlue;
    BYTE    rgbGreen;
    BYTE    rgbRed;
    BYTE    rgbReserved;
} RGBQUAD;

VB声明:

Private Type RGBQUAD
    rgbBlue As Byte
    rgbGreen As Byte
    rgbRed As Byte
    rgbReserved As Byte
End Type

说明:

rgbBlue

蓝色分量

rgbGreen

绿色分量

rgbRed

赤分量

rgbReserved#

保留,=0

员图数据

◆扫描行:
  一行的图像数据称一个扫描行。一个扫描行的长要是4之倍数(字节),如果无是,则用上一起。计算公式:LineBytes=((biWidth*biBitCount+31)And
&HFFFFFFE0)/8
  由于BMP设定者认为数学坐标系更总要,所以DIB的扫描行是逆序存储的(相对于屏幕坐标系而言),即屏幕上的首先推行是DIB位图数据的终极一行。

◆1位色:
  用1位表示一个像素,所以一个字节可以象征8只像素。坐标是自极度左边(最高位)开始之,而无是形似情形下的低位。在内存的张形式如下:

字节

0

7

6

5

4

3

2

1

0

像素

0

1

2

3

4

5

6

7

◆4位色:
  用4各表示一个像素,所以一个字节可以表示2只像素。坐标是自太左边(最高位)开始的,而不是一般景象下之低位。在内存的张形式如下:

字节

0

7

6

5

4

3

2

1

0

像素

0

1

像素位

3

2

1

0

3

2

1

0

◆8位色:
  用8各项表示一个像素,所以一个字节刚好只能表示一个像素。在内存的陈设形式如下:

字节

0

1

像素

0

1

◆16位色:
  用16号表示一个像素,所以个别单字节可以表示1只像素。默认情况下16各DIB是555格式,最高位无效(这对VB是个福音,因为VB没有16员无符号型)。在内存的摆设形式如下(PC机使用小端规则(little
endian),是低字节当前边):

字节

0

1

2

3

7

6

5

4

3

2

1

0

7

6

5

4

3

2

1

0

7

6

5

4

3

2

1

0

7

6

5

4

3

2

1

0

像素

0

1

RGB

G

B

x

R

G

G

B

x

R

G

RGB位

2

1

0

4

3

2

1

0

0

4

3

2

1

0

4

3

2

1

0

4

3

2

1

0

0

4

3

2

1

0

4

3

◆24位色:
  用24各项表示一个像素,所以三只字节可以代表1只像素。注意它的各个是BGR,而不是传统的RGB。在内存的摆形式如下:

字节

0

1

2

3

4

5

像素

0

1

RGB

B

G

R

B

G

R

◆32位色:
  用32各类表示一个像素,所以四个字节可以代表1单像素。注意绝大多数的GDI函数不会见处理Alpha通道(只有AlphaBlend支持)。在内存的摆设形式如下:

字节

0

1

2

3

4

5

6

7

像素

0

1

RGB

B

G

R

A

B

G

R

A

View 的核心工作原理

当 ActivityThread 中,当Activity被创造后会见以 DecorView 添加到 Window
中,同时创建 ViewRootImpl 对象,并以 ViewRootImpl 和 DecorView
建立关联,而 DecorView 就是一个 Activity 的世界级
View,在一个默认的主题中,它分成标题栏,和内容区域,我们所添加的 View
均是加上到了 DecorView 的情区域,这些被上加进去的 View
的劳作流程规范通过 ViewRootImpl 完成的。

ViewRoot、DecorView 及 View 的老三不行流程简介:

  • ViewRoot:对应于 ViewRootImpl,链接 WindowManager 和 DecorView
    的枢纽,View 的老三挺流程均是透过它们做到的。(View 的绘图流程是打
    ViewRoot 的 performTraversals() 方法开始之,它通过
    measure、layout、draw 三独流程最终才会将一个 View 完整的绘图出。)

  • DecorView:新建一个 Android
    应用时我们都知情,默认主题的情况下此动用的界面会分成两片:标题栏、内容区域。而者界面的世界级
    View 就是 DecorView。

  • View的绘图经过了 measure、layout、draw 三单流程:

  • measure:对应 onMeasure() 方法,测量View的宽、高。

  • layout:对应 onLayout()
    方法,确定view的季个顶,即确定View在父容器中的职位。
  • draw:对应 onDraw(),绘制View。在由定义 View 时咱们为亏以 onDraw()
    方法内可以在 Canvas 画布上任意的绘画生我们纪念要之 View。

六、结合DirectX

  以GDI中,我们得就此DIB直接操作图像数据,那么号称能够一直看显存的DirectX呢?

 

  一查DirectX
SDK,发现IDirectDrawSurface接口的Lock函数可以锁定表面,从而直接看该位图数据。再于VB的对象浏览器被仔细观察“DirectX
7 for Visual Basic Type Library”,发现DirectDrawSurface7对象也发生欠办法。

 

  看看5_DX7Ptr:

vb6/5_DX7Ptr/FrmMain.frm中Render
'渲染
Private Sub Render()
    Dim I As Long, J As Long
    Static K As Long
    Dim ddsdInfo As DDSURFACEDESC2
    Dim IsOK As Boolean
    Dim cbPitch As Long
    Dim cbPixel As Long
    Dim iIdxR As Long
    Dim iIdxG As Long
    Dim iIdxB As Long
    Dim iMaxX As Long, iMaxY As Long
    Dim pByte() As Byte, pBytePtr As SAFEARRAY1D
    Dim iLinePtr As Long

    ' check Image
    'Debug.Assert m_pDIB <> 0
    Debug.Assert Not m_ddsRender Is Nothing

    ' Main
    With m_ddsRender
        'Render
        Call .Lock(m_rctSurf, ddsdInfo, DDLOCK_SURFACEMEMORYPTR Or DDLOCK_WRITEONLY Or DDLOCK_NOSYSLOCK Or DDLOCK_WAIT, 0)
        IsOK = CheckPixelFormat(ddsdInfo.ddpfPixelFormat)
        If IsOK Then
            With ddsdInfo
                Debug.Assert .lpSurface
                cbPitch = .lPitch
                With .ddpfPixelFormat
                    cbPixel = (.lRGBBitCount) / 8
                    iIdxR = MaskToRShift(.lRBitMask) / 8
                    iIdxG = MaskToRShift(.lGBitMask) / 8
                    iIdxB = MaskToRShift(.lBBitMask) / 8
                End With
                iMaxX = .lWidth - 1
                iMaxY = .lHeight - 1
            End With

            '建立模拟指针
            MakePoint VarPtrArray(pByte), pBytePtr, 1

            Ptr(pBytePtr) = ddsdInfo.lpSurface
            iLinePtr = pBytePtr.pvData
            For I = 0 To iMaxY 'Y
                pBytePtr.pvData = iLinePtr
                For J = 0 To iMaxX 'X
                    'PicView.PSet (J, I), RGB(J And &HFF, I And &HFF, (J + K) And &HFF)
                    pByte(iIdxR) = J And &HFF       'Red
                    pByte(iIdxG) = I And &HFF       'Green
                    pByte(iIdxB) = (J + K) And &HFF 'Blue
                    pBytePtr.pvData = pBytePtr.pvData + cbPixel '下一个像素
                Next J
                iLinePtr = iLinePtr + cbPitch '下一个扫描行
            Next I

            '释放模拟指针
            FreePoint VarPtrArray(pByte)

        End If
        Call .Unlock(m_rctSurf)

        'Error Pixel Format
        If IsOK = False Then
            Call .BltColorFill(m_rctSurf, vbBlack)
            Call .SetForeColor(vbWhite)
            Call .DrawText(0, &H20, "Error Pixel Format!", False)
        End If

    End With

    K = (K + 1) And &HFF

End Sub

  1.出于硬件装备性能差,所以不要想像DIB那样可以肯定RGB字节顺序。应该根据Lock方法传回之DDSURFACEDESC2结构来确认RGB字节顺序(iIdxR、iIdxG、iIdxB)、像从所占用字节(cbPixel)及宽距(cbPitch)。
  2.由我们发出矣学指针技术,所以马上段代码和跟先前4_DIB_Ptr差不多,特别是跟在VC中使IDirectDrawSurface::Lock的处理代码差不多。

  仔细考察对象浏览器的人见面发觉,DirectDrawSurface7对象GetLockedArray可以获得锁定后底位图数据:

vb6/6_DX7Arr/FrmMain.frm中Render
'渲染
Private Sub Render()
    Dim I As Long, J As Long
    Static K As Long
    Dim ddsdInfo As DDSURFACEDESC2
    Dim IsOK As Boolean
    Dim cbPitch As Long
    Dim cbPixel As Long
    Dim iIdxR As Long
    Dim iIdxG As Long
    Dim iIdxB As Long
    Dim iMaxX As Long, iMaxY As Long
    Dim pByte() As Byte
    Dim iCurPtr As Long

    ' check Image
    'Debug.Assert m_pDIB <> 0
    Debug.Assert Not m_ddsRender Is Nothing

    ' Main
    With m_ddsRender
        'Render
        Call .Lock(m_rctSurf, ddsdInfo, DDLOCK_SURFACEMEMORYPTR Or DDLOCK_WRITEONLY Or DDLOCK_NOSYSLOCK Or DDLOCK_WAIT, 0)
        IsOK = CheckPixelFormat(ddsdInfo.ddpfPixelFormat)
        If IsOK Then
            With ddsdInfo
                Debug.Assert .lpSurface
                cbPitch = .lPitch
                With .ddpfPixelFormat
                    cbPixel = (.lRGBBitCount) / 8
                    iIdxR = MaskToRShift(.lRBitMask) / 8
                    iIdxG = MaskToRShift(.lGBitMask) / 8
                    iIdxB = MaskToRShift(.lBBitMask) / 8
                End With
                iMaxX = .lWidth - 1
                iMaxY = .lHeight - 1
            End With

            Call .GetLockedArray(pByte)

            For I = 0 To iMaxY 'Y
                iCurPtr = 0
                For J = 0 To iMaxX 'X
                    'PicView.PSet (J, I), RGB(J And &HFF, I And &HFF, (J + K) And &HFF)
                    pByte(iCurPtr + iIdxR, I) = J And &HFF      'Red
                    pByte(iCurPtr + iIdxG, I) = I And &HFF      'Green
                    pByte(iCurPtr + iIdxB, I) = (J + K) And &HFF 'Blue
                    iCurPtr = iCurPtr + cbPixel '下一个像素
                Next J
            Next I

        End If
        Call .Unlock(m_rctSurf)

        'Error Pixel Format
        If IsOK = False Then
            Call .BltColorFill(m_rctSurf, vbBlack)
            Call .SetForeColor(vbWhite)
            Call .DrawText(0, &H20, "Error Pixel Format!", False)
        End If

    End With

    K = (K + 1) And &HFF

End Sub

  这个就是是合法推荐做法,使用一个二维数组来处理各项图数据。但是就是是坐其采取的是二维数组,所以它们于同维数组的依样画葫芦指针慢有。如果您无思以特别技术(模拟指针),可以下GetLockedArray。
  注意到当下点并未,GetLockedArray是一个方而无是一个属性,我们需要以数组变量传递过去,然后便可行使该数组直接操作各图数据了。啊哈!明白了GetLockedArray也是行使模拟指针技术实现的,只不过它填充的是2维的SAFEARRAY结构而已。

  注意:只操作位于系统内存的表,千万别操作对显存中之标。这是因CPU看显存比返问内存要慢许多!这个提议并无是绝对的,如果对该表的Blt的调用次数多超常自己写的图像处理操作的话,可以用欠表在显存,或者是当内存中计算好后再也一次性交给至显存。
  本程序建立图像处理操作的标的代码:

vb6/5_DX7Ptr/FrmMain.frm中CreateSurfaces
    ' init Image
    With ddsdInfo
        .lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH Or DDSD_PIXELFORMAT
        With .ddsCaps
            .lCaps = DDSCAPS_OFFSCREENPLAIN Or DDSCAPS_SYSTEMMEMORY 'CPU访问内存比访问显存快
        End With
        .lWidth = ImgWidth
        .lHeight = ImgHeight
        .ddpfPixelFormat = m_ddsdInfo.ddpfPixelFormat
    End With
    Set m_ddsRender = m_dxDraw.CreateSurface(ddsdInfo)

(全文完)

匪明白怎么上污染文书,下载请到这边:
http://blog.gameres.com/thread.asp?BlogID=2143&threadid=55903

View是富有控件的基类,包括Button、TextView、EditView等等都直接或间接接轨自view,View下面还有ViewGroup子类,即LinearLayout、RelativeLayout等还属于ViewGroup。

从而VB写高效的图像处理程序 V2.0(2006-5-24)

自定义 View

打定义 View 的法子持续一种,可以直接接轨 View,重写 onDraw()
方法,也得一直接轨
ViewGroup,还好持续现有的控件(如:TextView、LinearLayout)等,本篇主要介绍一下直接轨
View 的章程。

直接接轨 View 来促成从定义 View
的这种方法较灵活,可以实现广大苛的法力,这种办法最好要紧的步骤就是是重写
onDraw() 方法,通过 Paint 画笔等工具在 Canvas
画布上拓展各种画的绘图以高达我们想只要之作用。

事实上当起定义 View
过程遭到,难点往往不是怎么利用画笔本身,而是绘制出预期效应的思绪,例如:你想透过打定义
View
来做一个折线图控件,传入一组数怎么规定这些多少以画布上对应点的相对坐标,而规定点的坐标就用通过有关的数学公式来计算了,推算出合适的公式往往就是釜底抽薪问题的显要。

连接下就因此这种措施来形容单圆形的略微 demo 来说明一下打定义 View 的流水线。

  • 新建一个累 View 的切近,添加构造方法,设置 Paint 画笔,重写 onDraw()
    方法,先在画布上为尽简便易行的道话一个半径为100的全面。

/**
 * 自定义 View 简单示例
 * Created by liuwei on 17/12/14.
 */
public class MyView extends View {

    private final static String TAG = MyView.class.getSimpleName();

    private Paint mPaint = new Paint();
    private int mColor = Color.parseColor("#ff0000");

    public MyView(Context context) {
        super(context);
        Log.i(TAG, "MyView(Context context):content=" + context);
        init();
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.i(TAG, "MyView(Context context, @Nullable AttributeSet attrs):content=" + context + " | attrs=" + attrs);
        init();
    }

    private void init() {
        mPaint.setAntiAlias(true); // 消除锯齿
        mPaint.setColor(mColor); // 为画笔设置颜色
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 重写此方法,对自定义控件在 wrap_content 情况下设置默认宽、高
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heithtSpecSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(200, 200);
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(200, heithtSpecSize);
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSpecSize, 200);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Log.i(TAG, "onDraw: ");
        super.onDraw(canvas);
        canvas.drawCircle(100, 100, 100, mPaint);
    }
}

运作结果虽是一个红的真切圆,在此示例中为了让布局文件中的
wrap_content 正常生效,重写了 onMeasure()
方法,关于这题目,在这篇博文《Android查缺补漏–自定义 View 中
wrap_content
无效的化解方案》遭遇为介绍了了,这里就是未多说了。

  • 用上面的圆再扩展一下:做成以画布的可用区域之中坚也圆点,画起极端充分的无所不包。同时也自定义
    View 设置 padding
    对于一个控件,有 margin 和 padding,margin
    是外间距,属于控件之外的限制,在由定义 View 时未待对 margin
    做特别处理。但 padding
    就不同了,是内距离,需要我们于控件的内部举行拍卖才能够吃布局文件被对控件设置的
    padding 生效。

private int mPaddingTop;
private int mPaddingBottom;
private int mPaddingLeft;
private int mPaddingRight;

private int mUsableWidth; // 可用宽度(减去padding后的宽度)
private int mUsableHeight;// 可用高度(减去padding后的高度)

private int mUsableStartX = 0; // 画笔起始点的x坐标
private int mUsableStartY = 0; // 画笔其实点的y坐标

private int mCircleX; // 圆心x坐标
private int mCircleY; // 圆心y坐标
private int mCircleRadius;// 圆的半径

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaddingTop = getPaddingTop();
    mPaddingBottom = getPaddingBottom();
    mPaddingLeft = getPaddingLeft();
    mPaddingRight = getPaddingRight();

    // 可用宽度和宽度要考虑padding
    mUsableWidth = getWidth() - mPaddingRight - mPaddingLeft;
    mUsableHeight = getHeight() - mPaddingTop - mPaddingBottom;
    // 画笔起始点要考虑padding
    mUsableStartX = mPaddingLeft;
    mUsableStartY = mPaddingTop;

    // 确定可用区域的中心为圆心
    mCircleX = mUsableStartX + mUsableWidth / 2;
    mCircleY = mUsableStartY + mUsableHeight / 2;

    // 确定圆的半径,以可用宽度和高度两者较短的一半为圆的半径
    if (mUsableWidth <= mUsableHeight) {
        mCircleRadius = mUsableWidth / 2;
    } else {
        mCircleRadius = mUsableHeight / 2;
    }

    canvas.drawCircle(mCircleX, mCircleY, mCircleRadius, mPaint);
}

每当布局文件中装置 paddingLeft 为15dp,paddingRight
为30dp,为了还好看出间距,将控件的背景颜色要为黑色,查看效果:

<cn.codingblock.view.reset_view.MyView
        android:id="@+id/myview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:paddingLeft="15dp"
        android:paddingRight="30dp"
        android:background="#000"/>

效果图:
图片 2

看得出,在 onDraw()
方法对padding处理以后,在布局文件被不管怎么设置padding,都能够确保圆心在可用区域之为主。

  • 为打定义 View 添加自定义属性

首先在 res/values 路径下创造一个xml文件,添加一个装置完善之颜色的性能:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView">
        <attr name="circle_color" format="color"/>
    </declare-styleable>
</resources>

当构造方法中解析属性

public MyView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.MyView);
    mColor = typeArray.getColor(R.styleable.MyView_circle_color, mColor);
    typeArray.recycle();
    init();
}

末尾在布局文件被立即是性就可以了,要小心的凡,在采用于定义属性时要补偿加
xmlns:app=”http://schemas.android.com/apk/res-auto” 才可以。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="cn.codingblock.view.activity.MyViewActivity">

    <cn.codingblock.view.reset_view.MyView
        android:id="@+id/myview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:paddingLeft="15dp"
        android:paddingRight="30dp"
        app:circle_color="#ad42ce"
        android:background="#000"/>

</LinearLayout>

改颜色后底效力图如下:
图片 3

同等、为什么这样慢?

  自盘古开天地吧(好像夸张了接触),一直有人抱怨VB程序速度缓慢。特别是图像处理,被看是VB的禁区。说起来为是,市面上之有关VB的图像处理的数据还是事先称计算公式,再一直用PSet(或API函数SetPixel)逐点画(至少我表现了的书写还是如此)。效果是办到了,但速度放缓得离谱:对平轴640*480之图像进行半晶莹剔透合并就用10秒钟;而在PhotoShop中,只要同设置图层的透明度,半晶莹剔透效果就展现。难怪有人说VB的闲谈。

 

  但就并无意味VB不可知写高速的图像处理程序,速度缓慢是盖从没行使科学的计。

 

  从VB5发端,能因为本机代码编译成exe文件,所以无在代码执行速度之问题。那么,是呀拖慢了快慢吗?就是PSet和SetPixel!PSet把浮点形式的坐标转为像素单位,再提交SetPixel处理。而SetPixel呢,坐标系转化、剪裁区域判断、将颜色相配吗装备支撑之无比接近的,最后还要根据不同的水彩格式寻址、为用颜色写副其所在位进行各类运算。经过这么多层处理,速度不慢才大。

 

  那么,怎样才能提高处理速度呢?使用DIB,直接指向位图所在内存进行操作,速度可以大大提高。现在瞧本文提供的范例程序的履进度,这只有是一个概括的情调演示程序。

 

图像尺寸:640*480*24b。单位:毫秒
  Debug Relase 说 明
1_PSet 1156.7042 936.2807 在VB使用 PSet 画的
2_SetPixelV 484.7545 460.5382 在VB使用 SetPixelV 画的
3_DIB 118.6978 3.8317 在VB使用 DIB 画的
4_DIB_Ptr 107.5791 4.3545 在VB使用 DirectDraw + 模拟指针 画的
5_DX7Ptr 108.1261 4.5503 在VB使用 DirectDraw + 模拟指针 画的
6_DX7Arr 131.8148 7.5506 在VB使用 DIBSection + GetLockedArray 画的
VC 2.8535 1.8994 用Visual C++ 6.0写的
我的电脑配置
CPU AMD Athlon XP 1700+(实际频率:1463 MHz (11 x 133))
内存 Kingston DDR266 256MB *2(两根)
显卡 nVIDIA GeForce2 MX/MX 400(AGP 4X,显存32MB)
测试环境 Windows XP sp2

图片 4
  从夫表中只是看:
  1.VC比3_DIB、4_DIB_Ptr快一些,这是以SafeArray结构的数组比真正的指针慢,但也未是少数人所说的70~100倍;
  2.4_DIB_Ptr比3_DIB慢一点,这是以学指针本来就是依SafeArray结构的累累组,需要以运作时动态修改数组数地址,所以速度缓慢一点;
  3.确差了70~100倍是1_PSet和2_SetPixelV。
  4.当VB
IDE中解释实施顺序非常缓慢,3_DIB就存30倍之速差距。所以经常有粗鄙的人头用
VC Debug编译的次 与 VB IDE中说施行顺序 比较快。
  5.4_DIB_Ptr、5_DX7Ptr速度一样,这是因还是使用模拟指针技术一直访问内存来做图像处理的。而6_DX7Arr使用的凡GetLockedArray返回的二维数组,二维数组比一维数组慢。

 

  以上可证,速度放缓的缘由是SetPixelV非常低效,而连无是VB的题目。虽然VC的真较快,但是我勾勒就首稿子不是以讨论速度极(否则就首文章会改名为《如何用汇编描绘高速的图像处理程序》),而是为了告知大家怎样以VB中描写能实时处理的图像处理程序。

 

  同时,决定代码速度的免是编程语言还是编译器,而是算法。如果算法写得差的言辞,无论你用啊编程语言或编译器,那次速度还是大缓慢(你于VC中因故SetPixelV写图像处理程序试试)。而今日的硬件配备都足足好,用VB完全好形容高速的图像处理程序。

 

ScaleGestureDetector 缩放手指检测

除此之外上面最常见的 MotionEvent 事件外,Android
还提供了成百上千有趣之轩然大波,就想
GestureDetector(手势检测)、VelocityTracker(速度追踪)等等,用起吧还死有利,其实要你肯,这些事件也全好以
onTouchEvent() 方法被落实,接下去当呢上述的旋 Demo
添加一个缩放的作用,也就算是利用 ScaleGestureDetector
实现,效果及平常以大哥大查照片时我们因此少彻底手指来放大/缩小图片相同。

ScaleGestureDetector
在用起来呢死简短,首先用初始化并也夫长一个放缩手势监听器,并且需要在
onTouchEvent() 方法内,通过 ScaleGestureDetector.onTouchEvent(event)
来深受 ScaleGestureDetector 接管触摸事件,其余的事项要留心看代码中之诠释。

每当上述代码的基本功及新增如下代码:

private Context mContext;
private ScaleGestureDetector mScaleGestureDetector; // 缩放手势检测
private float mScaleRate = 1; // 缩放比率

private void init() {
    mPaint.setAntiAlias(true); // 消除锯齿
    mPaint.setColor(mColor); // 为画笔设置颜色
    // 初始化 ScaleGestureDetector 并添加缩放手势监听器
    mScaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaddingTop = getPaddingTop();
    mPaddingBottom = getPaddingBottom();
    mPaddingLeft = getPaddingLeft();
    mPaddingRight = getPaddingRight();

    // 可用宽度和宽度要考虑padding
    mUsableWidth = getWidth() - mPaddingRight - mPaddingLeft;
    mUsableHeight = getHeight() - mPaddingTop - mPaddingBottom;
    // 画笔起始点要考虑padding
    mUsableStartX = mPaddingLeft;
    mUsableStartY = mPaddingTop;

    // 确定可用区域的中心为圆心
    mCircleX = mUsableStartX + mUsableWidth / 2;
    mCircleY = mUsableStartY + mUsableHeight / 2;

    // 确定圆的半径,以可用宽度和高度两者较短的一半为圆的半径
    if (mUsableWidth <= mUsableHeight) {
        mCircleRadius = mUsableWidth / 2;
    } else {
        mCircleRadius = mUsableHeight / 2;
    }

    // 让半径乘以缩放倍率
    mCircleRadius *= mScaleRate;
    canvas.drawCircle(mCircleX, mCircleY, mCircleRadius, mPaint);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mColor = mColors[mRandom.nextInt(6)];
            mPaint.setColor(mColor);
            invalidate(); // 通知控件重绘
            break;
        case MotionEvent.ACTION_UP:
            Log.i(TAG, "onTouchEvent: ACTION_UP");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.i(TAG, "onTouchEvent: ACTION_MOVE");
            break;
    }

    // 让缩放手势检测器接管触摸事件
    if (mScaleGestureDetector.onTouchEvent(event)) {
        return true;
    }

    return super.onTouchEvent(event);
}

private ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener = new ScaleGestureDetector.OnScaleGestureListener() {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        Log.i(TAG, "onScale: " + detector.getScaleFactor());
        // 获取缩放比例因子并累乘到缩放倍率上
        mScaleRate *= detector.getScaleFactor();
        postInvalidate();
        return true;
    }

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        Log.i(TAG, "onScaleBegin: " + detector.getScaleFactor());
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
        Log.i(TAG, "onScaleEnd: " + detector.getScaleFactor());
    }
};

图片 5

地方代码用留意的是,在 ScaleGestureDetector
捕获到事件后而科学的将事件消费掉(注意代码中归 true
的地方),不然缩放手势无法正常干活。

由定义 View 在 Android
中一直以来还是非常要紧的平片段,在平常底开想只要做出一个天性炫酷的互动界面是距离不上马于定义
View,自定义 View
说难不碍事,说简练也未略,总之,千里的实践,始于足下,只要我们掌握好自定义
View 的基础知识,再复杂的界面也可以一步步完。


末想说的凡,本系列文章也罢博主对Android知识进行再梳理,查缺补漏之学习过程,一方面是对准友好忘记的东西加以复习重新掌握,另一方面相信于重新学习的历程被必将会产生伟大的新取得,如果您也发出同自家同的想法,不妨关心自身一头读书,互相探讨,共同进步!

参考文献:

  • 《Android开发方探索》
  • 《Android开发进阶从小工到专家》

季、实战演习

  用DIB写图像处理程序的早晚,首先要显一点:DIB并无是图像处理算法,而是相同种植绘图方法。图像处理算法是DIB高级,管理坐标和颜色之演算;而DIB只是为着绘制。所以这拍卖算法的效率是快之首要。

 

  用DIB绘制图像并从未比用PSet/SetPixel绘制差小,它只是把坐标运算改成为地方运算而已。很多口知道指针是一个饮鸩止渴的物,就是坐它能一直看内存,如果指针不小心指错地方吧,Windows立即告诉一般保护性错误。所以,在地方运算的时刻自然要是小心,同时如果留心天天保存,因为这时候的非法操作的发生率非常高,否则辛辛苦苦写的代码一瞬间没了而是生成老我没提醒什么。

 

  好了,现在始发!

 

  由于拍卖算法起指导作用,所以现在先行称解1_PSet。所有的代码都当FrmMain.frm中。其他的历程的代码可以免扣,现在以注意力集中在“DrawIt”中,它就是是管绘制的。

 

vb6/1_PSet/FrmMain.frm中DrawIt
'绘制
Private Sub DrawIt()
    Dim I As Long, J As Long
    Static K As Long

    For I = 0 To ImgHeight - 1 'Y
        For J = 0 To ImgWidth - 1 'X
            PicView.PSet (J, I), RGB(J And &HFF, I And &HFF, (J + K) And &HFF)
        Next J
    Next I

    K = (K + 1) And &HFF

End Sub

  其实自己是演示程序非常简单的:R分量延着水平方向多,G分量延着垂直方向加,B分量则由右侧为左滚动。什么?!“And
&HFF”是啊意思?!这可基础啊……(下略&HFFFF…字)。“&H”表示十六向前制数,而And表示按位与。&HFF是二进制的“1111
1111”,正好覆盖了低8各类,这时用And进行按位与,只会拿走低8各,与RGB分量需要的8各刚刚吻合(对于“(J

  • K) And &HFF”来说,可以实现滚动效应)。

 

  If Not 看明白了 Then Goto 前少截

 

  好!现在打开3_DIB。(由于24各会一直指定RGB分量,所以这里是因此底凡24个DIB)

 

  看了面前的“DIB的结构”,是休是产生接触昏呢?其实DIB也远非什么,就是
一个发表位图信息之BITMAPINFO结构 和
一个囤员图数据的数量缓冲区,顶多重复就此SetDIBitsToDevice绘制,所以3_DIB与1_PSet相比就是多了SetDIBitsToDevice、BITMAPINFOHEADER(24各DIB没有调色板,所以用BITMAPINFOHEADER就行)和一些常数的扬言而已。由于斯演示程序不待改图像大小和质量生,所以可以将有关变量作为窗体级变量,再当Form_Load中初始化。由于DIB并不曾向系统报名资源(数组的内存是VB分配的,会自动释放),所以无待写释放代码。

 

  现在来拘禁DrawIt。

vb6/3_DIB/FrmMain.frm中DrawIt
'绘制
Private Sub DrawIt()
    Dim I As Long, J As Long
    Static K As Long
    Dim iLinePtr As Long, iCurPtr As Long

    iLinePtr = (m_BI.biHeight - 1) * m_LineBytes 'DIB是逆序存储的
    For I = 0 To ImgHeight - 1 'Y
        iCurPtr = iLinePtr
        For J = 0 To ImgWidth - 1 'X
            'PicView.PSet (J, I), RGB(J And &HFF, I And &HFF, (J + K) And &HFF)
            m_MapData(iCurPtr + 2) = J And &HFF       'Red
            m_MapData(iCurPtr + 1) = I And &HFF       'Green
            m_MapData(iCurPtr + 0) = (J + K) And &HFF 'Blue
            iCurPtr = iCurPtr + 3 '24位
        Next J
        iLinePtr = iLinePtr - m_LineBytes
    Next I

    K = (K + 1) And &HFF

End Sub

  1.尽管可逐点把坐标映射成地址再写,但是如此效率太没有了,可以使用坐标处理的连续性进行优化。
  2.出于我此用的是几度组,所以这里用(数组元素)索引代替地址。
  3.最好开始如留意DIB是逆序存储的,要将索引设为最后一实施第一单像从的目。
  4.由于DIB的RGB顺序是B、G、R,所以“m_MapData(CurIdx +
?)”的逐条是2、1、0。
  5.安好一个像素的颜色后,要小心把索引改吧下单像从的目。
  6.由于DIB是逆序存储的,移到下一个扫描行是“iLinePtr = iLinePtr –
m_LineBytes”

 


  “好了,代码看懂了,按F5运转看效果。”
  “咦?速度好像从来不抢多少啊?”


  这是出于程序在VB环境下是坐说明方式运行的,而说道对做图像处理所急需广大循环和大气的算术运算的实践效率非常没有,所以要是造译成(本机代码)exe还运行。此时还要注意编译优化,可以将“高级优化”的有勾打上,速度可提升20%左右。

 

啊于定义View添加交互事件

五、使用DIBSection和效仿指针

  虽然来GetDIBits/SetDIBits函数,但是DIB与GDI位图之间的数据交换还是要命不便利,特别处理过程中需要调用GDI函数来处理的时节。而且就是你便累,但如此做的处理效率很没有。所以Windows为我们提供了DIBSection。DIBSection是同种奇特之DIB,它除了可以像DIB一样直接针对各项图数据所占用内存进行操作,它还好选入DC、能用GDI函数绘制,非常灵活。但每当VB下采取DIBSection还是来困难的,因为用CreateDIBSection创建DIBSection时,得到的凡位图数据的地方,而VB没有指针。

 

  所幸以VB下足采取SafeArray结构的数组模拟指针。关于模拟指针的法则、方法,网上的材料多的凡,比如AdamBear的文章“VB真是怀念不至鳞次栉比的四:VB指针葵花宝典之SafeArray”。但这些章都只是是说道一般性的行使,不能够像真正的指针一样自由变更地址(他们还是下CopyMemory改的)。而以图像处理面临,由于触及运算的一再,“像真的指针一样随便更改地址”的功效非常重要。

 

  其实“像真的的指针一样自由更改地址”并从未技术难度(对于已学会模拟指针的人吧),就扣留想获取无:直接用一个动态数组(设pByte)指向一个SAFEARRAY结构体变量(设pBytePtr)。模拟指针模块的代码在mPoint.bas。

 

  现在来拘禁4_DIB_Ptr:

vb6/4_DIB_Ptr/FrmMain.frm中DrawIt
'绘制
Private Sub DrawIt()
    Dim I As Long, J As Long
    Static K As Long
    Dim pByte() As Byte, pBytePtr As SAFEARRAY1D
    Dim iLinePtr As Long

    ' check Image
    Debug.Assert m_pDIB <> 0

    '建立模拟指针
    MakePoint VarPtrArray(pByte), pBytePtr, 1

    Ptr(pBytePtr) = m_pDIB + (m_BI.biHeight - 1) * m_LineBytes 'DIB是逆序存储的
    iLinePtr = pBytePtr.pvData
    For I = 0 To ImgHeight - 1 'Y
        pBytePtr.pvData = iLinePtr
        For J = 0 To ImgWidth - 1 'X
            'PicView.PSet (J, I), RGB(J And &HFF, I And &HFF, (J + K) And &HFF)
            pByte(2) = J And &HFF       'Red
            pByte(1) = I And &HFF       'Green
            pByte(0) = (J + K) And &HFF 'Blue
            pBytePtr.pvData = pBytePtr.pvData + 3 '24位
        Next J
        iLinePtr = iLinePtr - m_LineBytes
    Next I

    '释放模拟指针
    FreePoint VarPtrArray(pByte)

    K = (K + 1) And &HFF

End Sub

  1.为演示DIBSection能够像HBITMAP一样,我当Form_Load中创造了DC、将DIBSection选入DC。同时为释放,Form_UnLoad中描写了放代码。
  2.于DrawIt中,注意处理局部的代码并无跟VB_DIB差多少,只不过把索引计算改为地方运算而已。

 

  再来比较vc的代码,感觉跟真正的指针用法差不多嘛:

vc/ImgTestDlg.cpp中CImgTestDlg::DrawIt
void CImgTestDlg::DrawIt() 
{
    int i=0,j=0;
    static int k=0;
    BYTE *pByte, *pLinePtr;

    pLinePtr = (BYTE*)pDIB + (bi.biHeight-1)*LineBytes;
    for(i=0; i<IMGHEIGHT; i++)
    {
        pByte = pLinePtr;
        for(j=0; j<IMGWIDTH; j++)
        {
            pByte[2] = j & 0xff;
            pByte[1] = i & 0xff;
            pByte[0] = (j+k) & 0xff;
            pByte = pByte + 3;
        }
        pLinePtr = pLinePtr - LineBytes;
    }

    k = (k+1) & 0xff;

}

咱俩用懂得的凡以Android中,无论是View还是任何界面,右方向表示正在x轴的正向,下方向代表正y轴的正向。

老三、DIB访问函数

SetDIBitsToDevice

原型定义:

int SetDIBitsToDevice(
  HDC hDC,              // handle to device context
  int XDest,            // x-coordinate of upper-left corner of dest. rect.
  int YDest,            // y-coordinate of upper-left corner of dest. rect.
  DWORD dwWidth,        // source rectangle width
  DWORD dwHeight,       // source rectangle height
  int XSrc,             // x-coordinate of lower-left corner of source rect.
  int YSrc,             // y-coordinate of lower-left corner of source rect.
  UINT uStartScan,      // first scan line in array
  UINT cScanLines,      // number of scan lines
  CONST VOID *lpvBits,  // address of array with DIB bits
  CONST BITMAPINFO *lpbmi,  // address of structure with bitmap info.
  UINT fuColorUse       // RGB or palette indexes
);

VB声明:

Declare Function SetDIBitsToDevice Lib “gdi32.dll” (ByVal hDC As Long,
ByVal XDest As Long, ByVal YDest As Long, ByVal dwWidth As Long, ByVal
dwHeight As Long, ByVal XSrc As Long, ByVal YSrc As Long, ByVal
uStartScan As Long, ByVal cScanLines As Long, lpvBits As Any, lpbmi As
Any, ByVal fuColorUse As Long) As Long

说明:

用一律幅及设备无关位图的任何还是局部数据直接复制到一个装备。这个函数在设施受到定义了一个对象矩形,以便接受各类图数据。它呢当DIB中定义了一个源矩形,以便从中提取数据

返回值:

若函数执行成功,返回欲复制的扫描线的多寡;如归时反复GDI_ERROR,表示来错

参数:

hDC

一个配备景的句柄。该现象用于吸纳各类图数据

XDest

点名绘制区域的左上角X坐标

YDest

指定绘制区域之左上角Y坐标

dwWidth

点名绘制区域之莫大

dwHeight

指定绘制区域之增幅

XSrc

矩形在DIB中之起点X坐标

YSrc

矩形在DIB中的起点Y坐标

uStartScan

lpvBits中首先长达扫描线的号。如lpbmi之BITMAPINFOHEADER部分的biHeight字段是正数,那么这长长的扫描线就会由位图的底层开始计算;如果是负数,就由顶部从头盘算

cScanLines

亟待复制的扫描线数量

lpvBits

针对一个缓冲区的指针。这个缓冲区包含了因DIB格式描述的位图数据;这种格式是由于lpbmi指定的

lpbmi

指向BITMAPINFO(为兼容BMP4/5万一声明成Any),对DIB的格式和颜料进行描述的一个组织

fuColorUse

DIB_PAL_COLORS 颜色表是一个整数数组,其中包含了与目前选入hDC设备场景的调色板相关的索引
DIB_RGB_COLORS 颜色表包含了RGB颜色

StretchDIBits

原型定义:

int StretchDIBits(
  HDC hDC,                // handle to device context
  int XDest,              // x-coordinate of upper-left corner of dest. rectangle
  int YDest,              // y-coordinate of upper-left corner of dest. rectangle
  int nDestWidth,         // width of destination rectangle
  int nDestHeight,        // height of destination rectangle
  int XSrc,               // x-coordinate of upper-left corner of source rectangle
  int YSrc,               // y-coordinate of upper-left corner of source rectangle
  int nSrcWidth,          // width of source rectangle
  int nSrcHeight,         // height of source rectangle
  CONST VOID *lpBits,            // address of bitmap bits
  CONST BITMAPINFO *lpBitsInfo,  // address of bitmap data
  UINT iUsage,                   // usage flags
  DWORD dwRop                    // raster operation code
);

VB声明:

Declare Function StretchDIBits Lib “gdi32” (ByVal hDC As Long, ByVal
XDest As Long, ByVal YDest As Long, ByVal nDestWidth As Long, ByVal
nDestHeight As Long, ByVal XSrc As Long, ByVal YSrc As Long, ByVal
nSrcWidth As Long, ByVal nSrcHeight As Long, lpBits As Any, lpBitsInfo
As Any, ByVal wUsage As Long, ByVal dwRop As Long) As Long

说明:

基于同样轴及设施无关之位图创建同幅及设备有关的位图

返回值:

尽成功返回位图句柄,零意味失败

参数:

hDC

一个装置景的句柄,该装备景定义了如果创造的跟设备有关位图的布局信息

XDest

点名绘制区域的左上角X坐标

YDest

指定绘制区域之左上角Y坐标

nDestWidth

点名绘制区域之莫大

nDestHeight

指定绘制区域之肥瘦

XSrc

矩形在DIB中之起点X坐标

YSrc

矩形在DIB中的起点Y坐标

nSrcWidth

点名原位图绘制区域之左上角X坐标

nSrcHeight

点名原位图绘制区域的左上角Y坐标

lpBits

本着一个缓冲区的指针。这个缓冲区包含了以DIB格式描述的位图数据;这种格式是由lpBitsInfo指定的

lpBitsInfo

指向BITMAPINFO(为兼容BMP4/5假设声明成Any),对DIB的格式和颜色进行描述的一个结构

iUsage

DIB_PAL_COLORS 颜色表是一个整数数组,其中包含了与目前选入hDC设备场景的调色板相关的索引
DIB_RGB_COLORS 颜色表包含了RGB颜色

dwRop

亟需进行的光栅运算

CreateDIBitmap

原型定义:

HBITMAP CreateDIBitmap(
  HDC hDC,                  // handle to device context
  CONST BITMAPINFOHEADER *lpbmih,  // pointer to bitmap size and format data
  DWORD fdwInit,            // initialization flag
  CONST VOID *lpbInit,      // pointer to initialization data
  CONST BITMAPINFO *lpbmi,  // pointer to bitmap color-format data
  UINT fuUsage              // color-data usage
);

VB声明:

Declare Function CreateDIBitmap Lib “gdi32” (ByVal hDC As Long, lpbmih
As Any, ByVal fdwInit As Long, lpbInit As Any, lpbmi As Any, ByVal
fuUsage As Long) As Long

说明:

将同幅及设备无关位图的满贯或者有数据直接复制到一个装置。这个函数在装置受到定义了一个对象矩形,以便接受各类图数据。它为在DIB中定义了一个源矩形,以便从中提取数额

返回值:

推行成功则回扫描线的数码,零象征失败。会装GetLastError

参数:

hDC

一个装备景的句柄。该场面用于收纳各类图数据

lpbmih

BITMAPINFOHEADER(为兼容BMP4/5若声明成Any),对DIB的格式进行描述的一个组织

fdwInit

假定未承诺本着各项图数据进行初始化,那么一旦为零星。如一旦为CBM_INIT,表示根据lpbInit和
lpbmi参数对各项图进行初始化

lpbInit

本着一个缓冲区的指针。这个缓冲区包含了坐DIB格式描述的位图数据;这种格式是出于lpbmi指定的

lpbmi

指向BITMAPINFO(为兼容BMP4/5万一声明成Any),对DIB的格式和颜料进行描述的一个布局

fuUsage

DIB_PAL_COLORS 颜色表是一个整数数组,其中包含了与目前选入hDC设备场景的调色板相关的索引
DIB_RGB_COLORS 颜色表包含了RGB颜色

CreateDIBSection

原型定义:

HBITMAP CreateDIBSection(
  HDC hDC,          // handle to device context
  CONST BITMAPINFO *lpbmi,
                    // pointer to structure containing bitmap size, format, and color data
  UINT iUsage,      // color data type indicator: RGB values or palette indexes
  VOID *ppvBits,    // pointer to variable to receive a pointer to  the bitmap's bit values
  HANDLE hSection,  // optional handle to a file mapping object
  DWORD dwOffset    // offset to the bitmap bit values within the file mapping object
);

VB声明:

Declare Function CreateDIBSection Lib “gdi32” (ByVal hDC As Long, lpbmi
As Any, ByVal iUsage As Long, ByRef ppvBits As Long, ByVal hSection As
Long, ByVal dwOffset As Long) As Long

说明:

CreateDIBSection能缔造同种植独特之DIB,称为DIB项(DIBSection),然后返回一个GDI位图的句柄。它提供了DIB和GDI位图的太好之特征。这样我们好直接访问DIB的内存,可以采取各类图句柄和内存设备条件,我们居然还足以于DIB中调用GDI函数来绘图

返回值:

执行成功返回DIBSection位图的句柄,零意味着失败。会设置GetLastError

参数:

hDC

一个设备景的句柄。如dw设为DIB_PAL_COLORS,那么DIB颜色表就会见就此来自逻辑调色板的水彩进行初始化

lpbmi

指向BITMAPINFO(为兼容BMP4/5一旦声明成Any),这个组织初始化成欲创建的那幅位图的安排数据

iUsage

DIB_PAL_COLORS 颜色表是一个整数数组,其中包含了与目前选入hDC设备场景的调色板相关的索引
DIB_RGB_COLORS 颜色表包含了RGB颜色

ppvBits

用于获取DIBSection数据区的内存地址

hSection

对一个文本映射对象的可选句柄,位图将以其中创建。如一旦为零星,Windows会自动分配内存

dwOffset

苟指定了句柄,就就此这个参数指定位图数据以文书映射对象被之偏移量

GetDIBits

原型定义:

int GetDIBits(
  HDC hDC,           // handle to device context
  HBITMAP hbmp,      // handle to bitmap
  UINT uStartScan,   // first scan line to set in destination bitmap
  UINT cScanLines,   // number of scan lines to copy
  LPVOID lpvBits,    // address of array for bitmap bits
  LPBITMAPINFO lpbmi,// address of structure with bitmap data
  UINT uUsage        // RGB or palette index
);

VB声明:

Declare Function GetDIBits Lib “gdi32” (ByVal hDC As Long, ByVal hbmp As
Long, ByVal uStartScan As Long, ByVal cScanLines As Long, lpvBits As
Any, lpbmi As Any, ByVal uUsage As Long) As Long

说明:

拖欠函数利用申请及的内存,由GDI各类图获得DIB各项图数据。通过该函数,可以本着DIB的格式进行支配,可以制定颜色之位数,而且可指定是否进行压缩。如果运用了压缩方式,则要调用该函数少不行,一不行为取所要内存,另外一不善以拿走位图数据

返回值:

执行成功则归扫描线的数,零意味着失败。会设置GetLastError

参数:

hDC

概念了和设备有关各图hBitmap的配置信息之一个配备景的句柄

hbmp

源位图的句柄

uStartScan

要复制到DIB中之首先长达扫描线的号码

cScanLines

欲复制的扫描线数量

lpvBits

针对一个缓冲区的指针。这个缓冲区包含了因DIB格式描述的位图数据;这种格式是出于lpbmi指定的

lpbmi

指向BITMAPINFO(为兼容BMP4/5如声明成Any).对DIB的格式和颜色进行验证的一个构造。在BITMAPINFOHEADER结构中,从biSize到biCompression之间的有所字段都要初始化

uUsage

DIB_PAL_COLORS 颜色表是一个整数数组,其中包含了与目前选入hDC设备场景的调色板相关的索引
DIB_RGB_COLORS 颜色表包含了RGB颜色

SetDIBits

原型定义:

int SetDIBits(
  HDC hDC,                  // handle to device context
  HBITMAP hbmp,             // handle to bitmap
  UINT uStartScan,          // starting scan line
  UINT cScanLines,          // number of scan lines
  CONST VOID *lpvBits,      // array of bitmap bits
  CONST BITMAPINFO *lpbmi,  // address of structure with bitmap data
  UINT uUsage               // type of color indexes to use
);

VB声明:

Declare Function SetDIBits Lib “gdi32” (ByVal hDC As Long, ByVal hbmp As
Long, ByVal uStartScan As Long, ByVal cScanLines As Long, lpvBits As
Any, lpbmi As Any, ByVal uUsage As Long) As Long

说明:

以自和装备无关位图的二进制位复制到均等轴及设备有关的位图里

返回值:

实施成功则回扫描线的数量,零表示失败。会安装GetLastError

参数:

hDC

概念了与装备有关各图hBitmap的布信息之一个设施景的句柄

hbmp

源位图的句柄

uStartScan

需复制到DIB中之率先漫长扫描线的号

cScanLines

要复制的扫描线数量

lpvBits

对一个缓冲区的指针。这个缓冲区包含了盖DIB格式描述的位图数据;这种格式是由于lpbmi指定的

lpbmi

指向BITMAPINFO(为兼容BMP4/5假如声明成Any).对DIB的格式和颜色进行求证的一个组织。在BITMAPINFOHEADER结构面临,从biSize到biCompression之间的具有字段都必须初始化

uUsage

DIB_PAL_COLORS 颜色表是一个整数数组,其中包含了与目前选入hDC设备场景的调色板相关的索引
DIB_RGB_COLORS 颜色表包含了RGB颜色

GetDIBColorTable

原型定义:

UINT GetDIBColorTable(
  HDC hDC,          // handle to device context whose DIB is of interest
  UINT uStartIndex, // color table index of first entry to retrieve
  UINT cEntries,    // number of color table entries to retrieve
  RGBQUAD *pColors  // pointer to buffer that receives color table entries
);

VB声明:

Declare Function GetDIBColorTable Lib “gdi32” (ByVal hDC As Long, ByVal
uStartIndex As Long, ByVal cEntries As Long, pColors As RGBQUAD) As Long

说明:

于选入设备景的DIBSection中获颜色表信息

返回值:

赢得回的颜色条目数量,零表示失败。会装GetLastError

参数:

hDC

曾选入了一个DIBSection对象的装备景

uStartIndex

颜色表中待抱回的第一单条款的目

cEntries

急需抱回之条文数量

pColors

是布局数组用于装载颜色表信息之第一个条款

SetDIBColorTable

原型定义:

UINT SetDIBColorTable(
  HDC hDC,                // handle to device context whose DIB is of interest
  UINT uStartIndex,       // color table index of first entry to set
  UINT cEntries,          // number of color table entries to set
  CONST RGBQUAD *pColors  // pointer to array of color table entries
);

VB声明:

Declare Function SetDIBColorTable Lib “gdi32” (ByVal hDC As Long, ByVal
uStartIndex As Long, ByVal cEntries As Long, pColors As RGBQUAD) As Long

说明:

自打选入设备景的DIBSection中落颜色表信息

返回值:

赢得回之颜料条目数量,零象征失败。会设置GetLastError

参数:

hDC

已选入了一个DIBSection对象的设备景

uStartIndex

颜色表中需抱回之率先个条文的目录

cEntries

亟需抱回之条规数量

pColors

以此组织数组用于装载颜色表信息的率先个条文

View是Android很要紧之一律片段,常用的View有Button、TextView、EditView、ListView、GridView、各种layout等等,开发者通过对这些View的各种组合为多变丰富多彩的互相界面,一个使用中界面交互的体验往往在运用之为欢迎程度及于了生重点得作用,所以开发者们基本上会千方百计的做出一个尤为出彩的界面,例如:通过由定义View、深入学习View的规律以便更好的对那个优化使其于操作起来更流畅等等,也刚好以这样,在面试中View也时常作为面试官重点考察之靶子之一。

作者:zyl910

一、为什么这么慢?
二、DIB的结构
三、DIB访问函数
四、实战练习
五、使用DIBSection和模拟指针
六、结合DirectX

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图