Android, IOS/Android

[Android Sutdio를 활용한 안드로이드 프로그래밍 개정 5판] 직접 풀어보기 8-2 및 응용

Emil :) 2019. 11. 23. 00:00
728x90
반응형

문제


  • SD카드에 있는 파일을 읽어와 이미지 뷰어를 만든다. 각각 이전 그림, 다음 그림 버튼이 있으며, 버튼 사이에 
    '현재 그림 번호 / 전체그림 개수' 텍스트뷰가 나타나게 한다.
  • 토스트 메시지를 없애고, 첫 번째 그림에서 <이전 그림>을 클릭하면 마지막 그림이, 마지막 그림에서 <다음 그림>을 클릭하면 첫 번째 그림이 나오게 한다.

결과 화면


에뮬레이터 sd카드에 이미지 넣는방법은 책에 써있으니 따로 쓰지 않겠다.

XML 코드


AndroidManifest.xml

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

SD카드 접근을 위해 매니페스트에 권한을 추가해주자.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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/btnPrev"
            android:layout_weight="1"
            android:text="이전 그림"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <TextView
            android:id="@+id/textView1"
            android:layout_width="80dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="1 / 5"/>
        <Button
            android:id="@+id/btnNext"
            android:layout_weight="1"
            android:text="다음 그림"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    </LinearLayout>
    <com.example.a1_mypictureview.MyPictureView
        android:id="@+id/myPictureView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

JAVA 코드


MyPictureView.java

package com.example.a1_mypictureview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

public class MyPictureView extends View {
    String imagePath = null;

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

    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        if(imagePath != null){
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
            canvas.drawBitmap(bitmap, 0, 0, null);
            bitmap.recycle();
        }
    }
}

 이미지뷰를 사용하는게 아니라 문제에서 커스텀뷰를 사용했으므로 커스텀뷰를 따로 만들어줘야한당

MainActivitiy.java

package com.example.a1_mypictureview;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;

public class MainActivity extends AppCompatActivity {

    Button btnPrev, btnNext;
    MyPictureView myPicture;
    int curNum = 0;
    File[] imageFiles;
    String imageFname;
    TextView textView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("간단 이미지 뷰어");
        ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE}, MODE_PRIVATE);

        //버튼 객체들 연결해주기
        btnPrev = findViewById(R.id.btnPrev);
        btnNext = findViewById(R.id.btnNext);
        myPicture = findViewById(R.id.myPictureView1);
        textView1 = findViewById(R.id.textView1);

        //첫 화면에 처음 이미지 파일을 띄워주기 위함이다.
        imageFiles = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures").listFiles();
        imageFname = imageFiles[0].toString();
        myPicture.imagePath=imageFname;

        //버튼에 리스너를 달아주자
        btnPrev.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //첫번째 그림이라면 imgeFiles[0]이므로 curNum은 0일것이다.
                //물론 초기값을 바꿔주려면 imageFiles[]의 숫자를 위에서 바꿔주면된다.
                //0인상태에서 이전을 누르면 0보다 작아질것이고, 이 경우 curNum을 배열 길이-1로 바꿔준다.
                //그리고 바뀐 curNum으로 imageFname에 다음 코드와 같이 적용시켜주면 끝!
                if(curNum <= 0) {
                    curNum = imageFiles.length-1;
                    imageFname = imageFiles[curNum].toString();
                    myPicture.imagePath = imageFname;
                    myPicture.invalidate();

                }
                else {
                    curNum--;
                    imageFname = imageFiles[curNum].toString();
                    myPicture.imagePath = imageFname;
                    myPicture.invalidate();
                }
                textView1.setText(curNum+1 + " / " + imageFiles.length);
            }
        });

        btnNext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //이전 버튼과 같은 매커니즘이다.
                if(curNum >= imageFiles.length-1) {
                    curNum = 0;
                    imageFname = imageFiles[curNum].toString();
                    myPicture.imagePath = imageFname;
                    myPicture.invalidate();
                }
                else {
                    curNum++;
                    imageFname = imageFiles[curNum].toString();
                    myPicture.imagePath = imageFname;
                    myPicture.invalidate();
                }
                textView1.setText(curNum+1 + " / " + imageFiles.length);

            }
        });

    }
}

결과


요로코롬 된당

 

 

추가 응용


과제로 커스텀 뷰를 사용하는 것이 아닌, 이미지뷰를 사용해서 같은 기능이 되도록 하는 것이 나왔다.

해보자!

xml코드는 커스텀 뷰 부분만 바꿔주면된다. java도 MyPictureView는 사용하지 않으므로 지워주자.

 

XML 코드


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">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/btnPrev"
            android:layout_weight="1"
            android:text="이전 그림"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <TextView
            android:id="@+id/textView1"
            android:layout_width="80dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textSize="20dp"/>
        <Button
            android:id="@+id/btnNext"
            android:layout_weight="1"
            android:text="다음 그림"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    </LinearLayout>
    <ImageView
        android:id="@+id/imageView1"
        android:scaleType="fitCenter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

JAVA 코드


MainActivity.java

package com.example.homework4;

import android.Manifest;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import java.io.File;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

public class MainActivity extends AppCompatActivity {

    Button btnPrev, btnNext;
    ImageView imageView1;
    int curNum = 0;
    File[] imageFiles;
    String imageFname;
    TextView textView1;
    Bitmap myBitmap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("이미지뷰를 이용한 이미지 뷰어");
        ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE}, MODE_PRIVATE);

        //xml 객체들 연결해주기
        btnPrev = findViewById(R.id.btnPrev);
        btnNext = findViewById(R.id.btnNext);
        imageView1 = findViewById(R.id.imageView1);
        textView1 = findViewById(R.id.textView1);

        //첫 화면으로 쓸 루트 지정해주기
        imageFiles = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures").listFiles();
        imageFname = imageFiles[0].toString();

        //기존 MyPictureView에 있던 비트맵 부분을 옮겨왔다.
        //Bitmap을 이용해 현재 이미지파일 이름을 가져와주고, setImageBitmap함수를 이용해서
        //첫 시작 화면 이미지뷰의 이미지를 설정해준다.
        myBitmap = BitmapFactory.decodeFile(imageFname);
        imageView1.setImageBitmap(myBitmap);
        textView1.setText(curNum+1 + " / " + imageFiles.length);

        btnPrev.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //기존 알고리즘과 비슷하고, 이미지뷰 이미지 설정만 다시 해주면된다!
                if(curNum <= 0) {
                    curNum = imageFiles.length-1;
                    imageFname = imageFiles[curNum].toString();
                }
                else {
                    curNum--;
                    imageFname = imageFiles[curNum].toString();
                }
                myBitmap = BitmapFactory.decodeFile(imageFname);
                imageView1.setImageBitmap(myBitmap);
                textView1.setText(curNum+1 + " / " + imageFiles.length);
            }
        });

        btnNext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(curNum >= imageFiles.length-1) {
                    curNum = 0;
                    imageFname = imageFiles[curNum].toString();
                }
                else {
                    curNum++;
                    imageFname = imageFiles[curNum].toString();
                }
                myBitmap = BitmapFactory.decodeFile(imageFname);
                imageView1.setImageBitmap(myBitmap);
                textView1.setText(curNum+1 + " / " + imageFiles.length);
            }
        });

    }
}

 

결과화면은 위와 같으니 따로 붙이진 않을 것이다.

비트맵에 대한 이해가 부족해서 조금 어려웠다.

728x90
반응형