Canvas API(3부)Matrix 및 drawBitmapMash에 대한 자세한 설명


이 섹션 소개:

Canvas의 API 문서에는 다음과 같은 메서드가 있습니다. drawBitmap(Bitmap bitmap, Matrix 행렬, 페인트 페인트)

이 행렬에는 큰 기사가 있습니다. 이전에 Paint API의 ColorFilter에 있는 ColorMatrix에 대해 설명한 적이 있습니다. 색상 매트릭스, 4 * 5 매트릭스, 매트릭스 값을 수정하여 색상, 채도 등을 수정할 수 있습니다! 오늘 우리가 이야기하고 있는 매트릭스는 다른 API와 결합하여 그래픽과 구성 요소의 변환을 제어할 수 있습니다. 예를 들어 Canvas는 위의 내용을 제공합니다. 이 drawBitmap은 행렬 변환 효과를 얻는 데 사용됩니다! 이 내용은 천천히 공부해 보세요~

공식 API 문서:Matrix


1. Matrix에서 일반적으로 사용되는 여러 변환 방법

  • setTranslate(float dx, float dy): Control Matrix Translates
  • setRotate (float 도, float px, float py): 회전, 매개변수는 다음과 같습니다: 회전 각도, 축(x, y)
  • setScale(float sx, float sy, float px, float py): 스케일링, 매개변수는 다음과 같습니다: X, Y축의 배율 비율
  • setSkew(float kx, float ky): 기울기(왜곡), 매개변수: X, Y축의 배율 비율

사실 기본적으로는 Canvas 변환 방법과 동일합니다. Matrix에 대해 위의 변환을 설정한 후 Canvas를 호출합니다. drawBitmap() 메서드는 행렬을 호출합니다~


2. 행렬 사용 예:

Running renders:

1.gif

Codeimplementation:

MyView.java:

/**
 * Created by Jay on 2015/11/11 0011.
 */
public class MyView extends View {

    private Bitmap mBitmap;
    private Matrix matrix = new Matrix();
    private float sx = 0.0f;          //设置倾斜度
    private int width,height;         //位图宽高
    private float scale = 1.0f;       //缩放比例
    private int method = 0;

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.img_meizi);
        width = mBitmap.getWidth();
        height = mBitmap.getHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        switch (method){
            case 0:
                matrix.reset();
                break;
            case 1:
                sx += 0.1;
                matrix.setSkew(sx,0);
                break;
            case 2:
                sx -= 0.1;
                matrix.setSkew(sx,0);
                break;
            case 3:
                if(scale  0.5){
                    scale -= 0.1;
                }
                matrix.setScale(scale,scale);
                break;
        }
        //根据原始位图与Matrix创建新图片
        Bitmap bitmap = Bitmap.createBitmap(mBitmap,0,0,width,height,matrix,true);
        canvas.drawBitmap(bitmap,matrix,null);    //绘制新位图
    }

    public void setMethod(int i){
        method = i;
        postInvalidate();
    }
}

레이아웃 코드: activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/ly_bar"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:layout_alignParentBottom="true">

        <Button
            android:id="@+id/btn_reset"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="重置" />

        <Button
            android:id="@+id/btn_left"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="左倾" />

        <Button
            android:id="@+id/btn_right"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="右倾" />

        <Button
            android:id="@+id/btn_zoomin"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="放大" />

        <Button
            android:id="@+id/btn_zoomout"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="缩小" />
    </LinearLayout>


    <com.jay.canvasdemo3.MyView
        android:id="@+id/myView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/ly_bar" />

MainActivity.java:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button btn_reset;
    private Button btn_left;
    private Button btn_right;
    private Button btn_zoomin;
    private Button btn_zoomout;
    private MyView myView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();
    }

    private void bindViews() {
        btn_reset = (Button) findViewById(R.id.btn_reset);
        btn_left = (Button) findViewById(R.id.btn_left);
        btn_right = (Button) findViewById(R.id.btn_right);
        btn_zoomin = (Button) findViewById(R.id.btn_zoomin);
        btn_zoomout = (Button) findViewById(R.id.btn_zoomout);
        myView = (MyView) findViewById(R.id.myView);


        btn_reset.setOnClickListener(this);
        btn_left.setOnClickListener(this);
        btn_right.setOnClickListener(this);
        btn_zoomin.setOnClickListener(this);
        btn_zoomout.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_reset:
                myView.setMethod(0);
                break;
            case R.id.btn_left:
                myView.setMethod(1);
                break;
            case R.id.btn_right:
                myView.setMethod(2);
                break;
            case R.id.btn_zoomin:
                myView.setMethod(3);
                break;
            case R.id.btn_zoomout:
                myView.setMethod(4);
                break;
        }
    }
}

사용법은 매우 간단해서 따로 설명하지 않겠습니다~


3. drawBitmapMash는 이미지를 왜곡합니다

에도 그런 방법이 있습니다. API 문서: drawBitmapMesh (Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, Paint Paint)

매개변수는 다음과 같습니다:

bitmap: 왜곡해야 하는 원본 비트맵

meshWidth/meshHeight: 원래 위치를 가로/세로로 배치 그림은 몇 개의 그리드로 나누어져 있나요?

verts: 길이가 (meshWidth+1)*(meshHeight+2)인 배열입니다. 왜곡된 비트맵(그리드선 교차점)의 각 꼭지점을 기록합니다. 위치는 1차원 배열이지만 실제로 기록하는 데이터는 (x0, y0), (x1, y1)..(xN, Yn) 형식입니다. 이러한 배열 요소는 비트맵에 대한 왜곡 효과를 제어합니다. bitmap

vertOffset: 비트맵을 왜곡할 배열 요소부터 시작하는 verts 배열을 제어합니다(verOffset 이전의 데이터 무시) 왜곡 효과)

2.png

코드 샘플 :

renning 렌더링 :

3.gif

코드 구현 :

/**
 * Created by Jay on 2015/11/11 0011.
 */
public class MyView extends View {

    //将水平和竖直方向上都划分为20格
    private final int WIDTH = 20;
    private final int HEIGHT = 20;
    private final int COUNT = (WIDTH + 1) * (HEIGHT + 1);  //记录该图片包含21*21个点
    private final float[] verts = new float[COUNT * 2];    //扭曲前21*21个点的坐标
    private final float[] orig = new float[COUNT * 2];    //扭曲后21*21个点的坐标
    private Bitmap mBitmap;
    private float bH,bW;


    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.img_wuliao);
        bH = mBitmap.getWidth();
        bW = mBitmap.getHeight();
        int index = 0;
        //初始化orig和verts数组。
        for (int y = 0; y <= HEIGHT; y++)
        {
            float fy = bH * y / HEIGHT;
            for (int x = 0; x <= WIDTH; x++)
            {
                float fx = bW * x / WIDTH;
                orig[index * 2 + 0] = verts[index * 2 + 0] = fx;
                orig[index * 2 + 1] = verts[index * 2 + 1] = fy;
                index += 1;
            }
        }
        //设置背景色
        setBackgroundColor(Color.WHITE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmapMesh(mBitmap, WIDTH, HEIGHT, verts
                , 0, null, 0, null);
    }

    //工具方法,用于根据触摸事件的位置计算verts数组里各元素的值
    private void warp(float cx, float cy)
    {
        for (int i = 0; i = 1)
            {
                verts[i + 0] = cx;
                verts[i + 1] = cy;
            }
            else
            {
                //控制各顶点向触摸事件发生点偏移
                verts[i + 0] = orig[i + 0] + dx * pull;
                verts[i + 1] = orig[i + 1] + dy * pull;
            }
        }
        //通知View组件重绘
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        //调用warp方法根据触摸屏事件的座标点来扭曲verts数组
        warp(event.getX(), event.getY());
        return true;
    }

}

implementation process analysis : first의 첫 번째, 당신은이 동점에 저장된 내용을 알아 내야합니다. 정렬? 예를 들어 Verts[0] 및 verts

1
, 이 두 개의 인접한 요소는 실제로 첫 번째 점의 x 좌표와 y 좌표를 나타냅니다! 이것을 알면 포인트가 21 * 21인 이유와 배열 길이가 이 값 * 2와 같은 이유를 알 수 있습니다! 초기화 부분을 이해하게 되실 겁니다!

그런 다음 터치 이벤트를 기반으로 verts 배열 요소의 값을 계산하는 구현을 살펴보겠습니다. 터치 지점의 x, y 좌표를 구하고 해당 지점의 x, y 좌표에서 이 값을 뺀 후 터치 지점과 각 좌표 지점 사이의 거리를 계산합니다. 그런 다음 소위 왜곡 정도를 계산합니다. 80000 / ((float) (dd * d)) 왜곡 정도가 1보다 크면 좌표를 직접 지정합니다. 포인트가 이 터치 포인트를 가리키는 경우 < 1, 각 꼭지점은 터치 포인트로 오프셋된 다음 무효화()가 호출되어 다시 그려집니다~ 바로 그거예요~ 더 생각하고 더 생각해보세요. 그래도 이해가 안 된다면, 이런 게 있다는 걸 알아두면 좋아요!

4 이 섹션의 예를 다운로드하세요.

CanvasDemo3.zip

CanvasDemo4.zip

이 섹션 요약:


이 섹션의 대부분의 콘텐츠는 - Li에서 발췌되었습니다. 갱의 '안드로이드' 크레이지 유인물, 좀 더 이해하기 쉬울지도 모르겠네요~ 매트릭스는 대부분의 어린이가 이해할 수 있어야 하지만 drawBitmapMash는 이미지를 왜곡하는 데 시간이 걸릴 수 있습니다. 소화하고 소화할 시간, 이해가 안 되셔도 괜찮아요~ 자, 여기까지입니다. 감사합니다

4.gif