実践例を描く


このセクションの紹介:

最初の 2 つのセクションでは、ビットマップといくつかの基本的な描画 API プロパティと一般的なメソッドを学習しましたが、常に少しばかり感じていました。 実践的でない場合は、イメージを深めるために何かを書く必要がありますよね? さて、このセクションでは 2 つの簡単な例を書きます:

  • 1. 簡単な描画ボードの実装
  • 2.美しい女性の服の掃除を手伝っています


ふふ、2 番目の例は、Android を学んだばかりの Xiaozhu が書いた小さなデモです~ふふ~ このセクションを始めましょう~


1. 実践例 1: 簡単な描画ボードの実装:

多くの携帯電話には、ユーザーが落書きするための描画ボードが付属していると思います。 1つの簡単な 例として、まず、これを実装するためのロジックをいくつか分析してみましょう:

Q1: この製図板はどこに配置されていますか?

回答: View では、View をカスタマイズし、onDraw() で描画を完了します。さらに、View には onTouchEvent メソッドもあります。 ユーザーのジェスチャー操作を取得できる!

Q2.何を準備する必要がありますか?

答え: ペイントブラシ (Paint)、キャンバス (Canvas)、およびパス (Path) は、ユーザーが描いたルートを記録します。 さらに、線を描くときは、毎回、最後のドラッグ時間が発生した点から現在のドラッグ時間が発生する点までです。じゃあ前に描いたものは 以前に描画したコンテンツを保存するために、いわゆる「ダブルバッファリング」テクノロジーを導入できます。 実際には、毎回 Canvas に直接描画されるのではなく、最初に Bitmap に描画され、Bitmap への描画が完了した後、 一度にビューに描画するだけです。

Q3.具体的な導入プロセスはどのようなものですか?

答え: ブラシを初期化し、色やその他のパラメーターを設定し、View の onMeasure() メソッドで View サイズのビットマップを作成します。 同時に Canvas を作成し、onTouchEvent で X 座標と Y 座標を取得し、接続を描画し、最後に validate() を使用して再描画します。 onDraw メソッドは、ビットマップの内容を Canvas 上に描画します。

ロジックはわかったので、コードは次のとおりです:

MyView.java:

/**
 * Created by Jay on 2015/10/15 0015.
 */
public class MyView extends View{

    private Paint mPaint;  //绘制线条的Path
    private Path mPath;      //记录用户绘制的Path
    private Canvas mCanvas;  //内存中创建的Canvas
    private Bitmap mBitmap;  //缓存绘制的内容

    private int mLastX;
    private int mLastY;

    public MyView(Context context) {
        super(context);
        init();
    }

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

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

    private void init(){
        mPath = new Path();
        mPaint = new Paint();   //初始化画笔
        mPaint.setColor(Color.GREEN);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND); //结合处为圆角
        mPaint.setStrokeCap(Paint.Cap.ROUND); // 设置转弯处为圆角
        mPaint.setStrokeWidth(20);   // 设置画笔宽度
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        // 初始化bitmap,Canvas
        mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    //重写该方法,在这里绘图
    @Override
    protected void onDraw(Canvas canvas) {
        drawPath();
        canvas.drawBitmap(mBitmap, 0, 0, null);
    }

    //绘制线条
    private void drawPath(){
        mCanvas.drawPath(mPath, mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                mPath.moveTo(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = Math.abs(x - mLastX);
                int dy = Math.abs(y - mLastY);
                if (dx > 3 || dy > 3)
                    mPath.lineTo(x, y);
                mLastX = x;
                mLastY = y;
                break;
        }

        invalidate();
        return true;
    }
}

Running renderings:

1.gif

Modify を追加するなど、ニーズに応じて拡張できます。ブラシのサイズ、ブラシの色の変更、独自の描画の保存など。 発散的に考えて、自分で実行してください~


2. 実践例 2: 美しい女性の服を消去する実現

中心となるアイデアは次のとおりです。 フレームレイアウトを利用して、前後2つのImageViewが存在し、前者は衣服を拭き取る前の状態、後者は衣服を拭き取った後の様子を示しています。

2 つの ImageView に美しい写真を設定した後、前の ImageView に OnTouchListener を設定します。ここに指を タッチポイント付近の20*20ピクセルを透明に設定してください。

レンダリングの実行:

2.gif

コード実装:

ステップ 1: 女の子の選択に関連する最初のアクティビティ、最初はインターフェイス、ImageView、ボタン、ギャラリーです。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/img_choose"
        android:layout_width="320dp"
        android:layout_height="320dp" />

    <Button
        android:id="@+id/btn_choose"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="脱光她!" />

    <Gallery
        android:id="@+id/gay_choose"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="25dp"
        android:spacing="1pt"
        android:unselectedAlpha="0.6" />

</LinearLayout>

次に、GalleryのAdapterクラスを書き換えます。内部の画像を表示するのは比較的簡単です。 別のレイアウトを記述する必要はありません。

MeiziAdapter.java:

/**
 * Created by Jay on 2015/10/16 0016.
 */
public class MeiziAdapter extends BaseAdapter{

    private Context mContext;
    private int[] mData;

    public MeiziAdapter() {
    }

    public MeiziAdapter(Context mContext,int[] mData) {
        this.mContext = mContext;
        this.mData = mData;
    }

    @Override
    public int getCount() {
        return mData.length;
    }

    @Override
    public Object getItem(int position) {
        return mData[position];
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView imgMezi = new ImageView(mContext);
        imgMezi.setImageResource(mData[position]);         //创建一个ImageView
        imgMezi.setScaleType(ImageView.ScaleType.FIT_XY);      //设置imgView的缩放类型
        imgMezi.setLayoutParams(new Gallery.LayoutParams(250, 250));    //为imgView设置布局参数
        TypedArray typedArray = mContext.obtainStyledAttributes(R.styleable.Gallery);
        imgMezi.setBackgroundResource(typedArray.getResourceId(R.styleable.Gallery_android_galleryItemBackground, 0));
        return imgMezi;
    }
}

最後に、アクティビティに進みます。これも非常に簡単で、ボタンをクリックした後、現在選択されているギャラリーの onSelected イベントを設定するだけです。 位置が次のページに引き継がれます。

MainActivity.java

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener,
        View.OnClickListener {

    private Context mContext;
    private ImageView img_choose;
    private Button btn_choose;
    private Gallery gay_choose;
    private int index = 0;
    private MeiziAdapter mAdapter = null;
    private int[] imageIds = new int[]
            {
                    R.mipmap.pre1, R.mipmap.pre2, R.mipmap.pre3, R.mipmap.pre4,
                    R.mipmap.pre5, R.mipmap.pre6, R.mipmap.pre7, R.mipmap.pre8,
                    R.mipmap.pre9, R.mipmap.pre10, R.mipmap.pre11, R.mipmap.pre12,
                    R.mipmap.pre13, R.mipmap.pre14, R.mipmap.pre15, R.mipmap.pre16,
                    R.mipmap.pre17, R.mipmap.pre18, R.mipmap.pre19, R.mipmap.pre20,
                    R.mipmap.pre21
            };

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

    private void bindViews() {
        img_choose = (ImageView) findViewById(R.id.img_choose);
        btn_choose = (Button) findViewById(R.id.btn_choose);
        gay_choose = (Gallery) findViewById(R.id.gay_choose);


        mAdapter = new MeiziAdapter(mContext, imageIds);
        gay_choose.setAdapter(mAdapter);
        gay_choose.setOnItemSelectedListener(this);
        btn_choose.setOnClickListener(this);

    }


    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        img_choose.setImageResource(imageIds[position]);
        index = position;
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
    }

    @Override
    public void onClick(View v) {
        Intent it = new Intent(mContext,CaClothes.class);
        Bundle bundle = new Bundle();
        bundle.putCharSequence("num", Integer.toString(index));
        it.putExtras(bundle);
        startActivity(it);
    }
}

次に、女の子の服を拭き取るページは、FrameLayout + 前後の 2 つの ImageView を備えた比較的単純なものです。 Java コードの一部:

CaClothes.java:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/img_after"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:id="@+id/img_before"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</FrameLayout>

コードは理解するのが難しくはありませんが、それでも比較的単純です。あまり多くの右手を使用しないでください。スパイラルルール... ..

3. コードサンプルのダウンロード:

3.gifDrawDemo1.zip

プロジェクトは比較的大きく、20M を超えており、多くの画像リソースがありますね~

これの概要セクション:

さて、このセクションでは、非常に興味深い 2 つの小さな例を書きました。美しい女性の服はどこにありますか? 消去するとブロックの形になりますが、大丈夫です。次のセクションで複数の PorterDuff について学習します。 このコードと比較して、さらにサンプルを書いてみましょう。また、時間の制約のため、コードは最適化されていません。 または、整理したり、自分のニーズに応じて変更したりすることもできます~はい、以上です。皆様にとって幸せな週末をお過ごしください~