느린 것을 걱정하지 말고, 멈춰서는 것을 걱정하라
article thumbnail

안드로이드 그림판을 만들어 보았다. 색상을 선택할 수 있도록 하였고 선의 끝부분을 달리할 수 있게 하였으며 굴기를 선택할 수 있게 하였다. 너무나도 재미있다.

 

 

기능)

1. 그림 그리기

2. 색상 선택

3. 굵기 선택

4. 선끝모양 설정

 

 

배운것)

1. OpenSource중 ColorPicker를 쉽게 해주는 오픈소스가 있다는 것을 발견함.

2. 다양한 그림 그리는 방법을 익힘.

3. 다이얼로그 사용법을 익힘.

 

 

 

 

 

MainActivity.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package org.techtown.paintboard;
 
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
 
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle;
import android.text.InputType;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
 
import yuku.ambilwarna.AmbilWarnaDialog;
 
public class MainActivity extends AppCompatActivity {
 
    MyPaintView view;
    int tColor,n=0;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        view = new MyPaintView(this);
 
        LinearLayout container = findViewById(R.id.container);
        Resources res = getResources();
 
 
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
        container.addView(view, params);
 
        RadioButton rBtn1 = findViewById(R.id.radioButton);
        RadioButton rBtn2 = findViewById(R.id.radioButton2);
        RadioButton rBtn3 = findViewById(R.id.radioButton3);
 
        RadioGroup radioGroup = findViewById(R.id.radioGroup);
        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId) {
                    case R.id.radioButton:
                        view.setCap(0);
                        break;
                    case R.id.radioButton2:
                        view.setCap(1);
                        break;
                    case R.id.radioButton3:
                        view.setCap(2);
                        break;
                }
            }
        });
 
        Button btn=findViewById(R.id.colorPickerButton);
        Button btn2=findViewById(R.id.thickPickerButton);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                openColorPicker();
            }
        });
        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                show();
            }
        });
    }
 
    private void show() {
        final EditText editText=new EditText(this);
        editText.setInputType(InputType.TYPE_CLASS_NUMBER);
 
 
        AlertDialog.Builder builder=new AlertDialog.Builder(this);
        builder.setTitle("AlertDialog Title");
        builder.setMessage("굵기 입력");
        builder.setView(editText);
        builder.setPositiveButton("입력",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        view.setStrokeWidth(Integer.parseInt(editText.getText().toString()));
 
                    }
                });
        builder.setNegativeButton("취소",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
 
                    }
                });
        builder.show();
 
    }
 
    private void openColorPicker() {
        AmbilWarnaDialog colorPicker = new AmbilWarnaDialog(this, tColor, new AmbilWarnaDialog.OnAmbilWarnaListener() {
            @Override
            public void onCancel(AmbilWarnaDialog dialog) {
 
            }
 
            @Override
            public void onOk(AmbilWarnaDialog dialog, int color) {
                Toast.makeText(getApplicationContext(),""+tColor,Toast.LENGTH_LONG).show();
                view.setColor(color);
            }
        });
        colorPicker.show();
    }
 
}
 
cs

 



MyPaintView.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package org.techtown.paintboard;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
 
import androidx.annotation.Nullable;
 
public class MyPaintView extends View {
 
    public boolean changed = false;
 
    Canvas mCanvas;
    Bitmap mBitmap;
    Paint mPaint;
 
    float lastX;
    float lastY;
 
    Path mPath = new Path();
 
    float mCurveEndX;
    float mCurveEndY;
 
    int mInvalidateExtraBorder = 10;
 
    static final float TOUCH_TOLERANCE = 8;
 
    public MyPaintView(Context context) {
        super(context);
        init(context);
    }
 
    public MyPaintView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
 
    private void init(Context context) {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
 
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(3.0F);
 
        this.lastX = -1;
        this.lastY = -1;
    }
 
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        Bitmap img = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas();
        canvas.setBitmap(img);
        canvas.drawColor(Color.WHITE);
 
        mBitmap = img;
        mCanvas = canvas;
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap != null) {
            canvas.drawBitmap(mBitmap, 00null);
        }
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_UP:
                changed = true;
                Rect rect = touchUp(event, false);
                if (rect != null) {
                    invalidate(rect);
                }
                mPath.rewind();
 
                return true;
            case MotionEvent.ACTION_DOWN:
                rect = touchDown(event);
                if (rect != null) {
                    invalidate(rect);
                }
 
                return true;
            case MotionEvent.ACTION_MOVE:
                rect = touchMove(event);
                if (rect != null) {
                    invalidate(rect);
                }
                return true;
 
        }
        return false;
    }
 
    private Rect touchMove(MotionEvent event) {
        Rect rect=processMove(event);
        return rect;
    }
 
    private Rect processMove(MotionEvent event) {
        final float x=event.getX();
        final float y=event.getY();
 
        final float dx=Math.abs(x-lastX);
        final float dy=Math.abs(y-lastY);
 
        Rect mInvalidateRect=new Rect();
 
        if(dx>=TOUCH_TOLERANCE || dy>=TOUCH_TOLERANCE){
            final int border=mInvalidateExtraBorder;
 
            mInvalidateRect.set((int)mCurveEndX-border,(int)mCurveEndY-border,(int)mCurveEndX+border,(int)mCurveEndY+border);
 
            float cx=mCurveEndX=(x+lastX)/2;
            float cy=mCurveEndY=(y+lastY)/2;
 
            mPath.quadTo(lastX,lastY,cx,cy);
 
            mInvalidateRect.union((int)lastX-border,(int)lastY-border,(int)lastX+border,(int)lastY+border);
            mInvalidateRect.union((int)cx-border,(int)cy-border,(int)cx,(int)cy+border);
 
            lastX=x;
            lastY=y;
 
            mCanvas.drawPath(mPath,mPaint);
 
        }
 
        return mInvalidateRect;
    }
 
    private Rect touchDown(MotionEvent event) {
        float x=event.getX();
        float y=event.getY();
 
        lastX=x;
        lastY=y;
 
        Rect mInvalidateRect=new Rect();
        mPath.moveTo(x,y);
 
        final int border=mInvalidateExtraBorder;
        mInvalidateRect.set((int)x-border,(int)y-border,(int)x+border,(int)y+border);
        mCurveEndX=x;
        mCurveEndY=y;
 
        mCanvas.drawPath(mPath,mPaint);
        return mInvalidateRect;
    }
    public void setStrokeWidth(int width){
        mPaint.setStrokeWidth(width);
    }
 
    private Rect touchUp(MotionEvent event, boolean b) {
        Rect rect=processMove(event);
        return rect;
    }
 
    public void setColor(int color){
        mPaint.setColor(color);
 
    }
    public void setCap(int cap){
        switch(cap){
            case 0:
                mPaint.setStrokeCap(Paint.Cap.BUTT);
                break;
            case 1:
                mPaint.setStrokeCap(Paint.Cap.ROUND);
                break;
            case 2:
                mPaint.setStrokeCap(Paint.Cap.SQUARE);
                break;
        }
    }
}
 
cs

 

activity_main.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?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=".MainActivity" >
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
 
        <Button
            android:id="@+id/colorPickerButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="색상선택" />
 
        <Button
            android:id="@+id/thickPickerButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="굵기입력" />
 
 
    </LinearLayout>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
 
        <RadioGroup
            android:id="@+id/radioGroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
 
            <RadioButton
                android:id="@+id/radioButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="BUTT" />
 
            <RadioButton
                android:id="@+id/radioButton2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="ROUND" />
 
            <RadioButton
                android:id="@+id/radioButton3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="SQUARE" />
        </RadioGroup>
 
    </LinearLayout>
 
    <LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"></LinearLayout>
</LinearLayout>
cs

build.gradle.xml (app)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "org.techtown.paintboard"
        minSdkVersion 15
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
 
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    dependencies { implementation 'com.github.yukuku:ambilwarna:2.0.1' }
}
 
cs

 

profile

느린 것을 걱정하지 말고, 멈춰서는 것을 걱정하라

@주현태

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!