Tạo ứng dụng nhật ký cá nhân android sử dụng kỹ thuật Custom View

I.Mở đầu

1. Giới thiệu

Xin chào các bạn hôm nay mình sẽ giới thiệu với các bạn cách để thiết kế lại một view có sẵn của UI android hay còn gọi là custom view. Vì Android là một bộ mã nguồn mở cho nên việc custom view theo phong cách cá nhân là một lợi thế hơn bất kỳ mã nguồn mobile nào hiện có (IOS, WINDOW 10, BBOS) Và project để làm mẫu thì mình sẽ hướng dẫn các bạn tự làm một ứng dụng nhật ký cá nhân với tiêu chí nhanh, đơn giản nhưng vẫn đẹp và dễ sử dụng. diary.png

2. Chuẩn bị

Trước hết chúng ta cần phải biết chuẩn bị những gì trước khi bắt tay vào code: Bạn cần có một kiến thức sơ bộ về lập trình android (Hiểu cách cài đặt IDE để lập trình, tạo project mới từ IDE và biết một số control cơ bản của hệ điều hành android.) Bạn cũng cần có một số kỹ năng cơ bản về tiếng anh để tìm tài liệu nếu không hiểu hoặc muốn hiểu sâu bằng cách sử dụng google, yahoo, bing search… Nếu bạn đã đáp ứng đủ các yêu cầu ở trên thì chúng ta bắt đầu nào.

II. Coding

Chúng ta sẽ thực hiện step by step

1. Khởi tạo project

Khởi tạo project bằng IDE. Ở đây mình dùng eclipse để tạo, mình lấy tên là Framgia Diary và package name là com.framgia.diary

2. Quản trị dữ liệu

Để làm được một ứng dụng nhật ký thì bạn cần 1 database(db) để quản trị dữ liệu dễ dàng, cụ thể là để lưu, chỉnh sửa nhật ký hàng ngày.

3. Coding

3.1 Thiết kế database (db) để lưu trữ nhật ký hàng ngày

Để cho công việc được nhanh chóng thì ở đây mình sử dụng database (db) là SqlLite và một thư viện hỗ trợ cho việc quản lý nó là Sugar ORM một thư viện được nhiều người dùng và khá nổi tiếng trên trang web github. Chúng ta tạo 1 bảng có tên là Diary luôn với cấu trúc:

public class Diary extends SugarRecord implements Serializable {
    private static final long serialVersionUID = 1L;
    public long created_date;
    public long update_date;
    public String content;
    public boolean deleted;

    public Diary() {
        super();
    }

    public Diary(String content) {
        this.content = content;
    }
}

Và khai báo thư mục model (bảng sẽ tạo bởi sugar) trong file manifest.xml cũng như các setting khác của database.

<application>
         <meta-data
            android:name="DATABASE"
            android:value="diary.db" />
        <meta-data
            android:name="VERSION"
            android:value="1" />
        <meta-data
            android:name="QUERY_LOG"
            android:value="true" />
       <meta-data
            android:name="DOMAIN_PACKAGE_NAME"
            android:value="com.framgia.diary.model" />
    </application>

Mình đặt tên cho db là diary.db và các bảng ở trong package com.framgia.diary.model

3.2 Thiết kế giao diện hiển thị

3.2.1 Bạn có thể chọn bất kỳ kiểu thiết kế giao diện nào mà bạn thấy ưng ý. Project này thì mình chọn hiển thị nhật ký hàng ngày dưới dạng gridview nhé (giống với app đọc truyện kindle nổi tiếng của amazon ^^ )

device-2015-11-24-125714.png

3.2.2 Trên các nhật ký thì mình sẽ cho hiện tóm tắt ngắn của trang nhật ký đó.

3.2.3 Xây dựng control để biên soạn 1 trang nhật ký mới

Click vào button + trên actionbar sẽ di chuyển qua màn hình thêm mới. Click vào các trang nhật ký để đọc và chỉnh sửa.

4. Tạo nhật ký

4.1. Custom edittext view

Để biên soạn và hiển thị nhật ký thì chúng ta cần 1 control của android là EditText. Đầu tiên chúng ta khởi tạo 1 class SecondLineEditText kế thừa từ EditText trong “package com.framgia.diary.customview;” như sau:

public class SecondLineEditText extends EditText {
    private Bitmap bitmap;
    private boolean editable;

    public SecondLineEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initData(context);
    }

    public SecondLineEditText(Context context) {
        super(context);
        initData(context);
    }

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

Phù mệt quá, bạn nghỉ ngơi ít phút để chuẩn bị vào bước quan trọng nào. Bạn có nhìn thấy method name “initData(context);”. Tôi cá là bạn có thấy đấy, đó là method để chúng ta khởi tạo những biến cần thiết để bắt đầu việc chế biến view

private void initData(Context context) {
        mRect = new Rect();
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setColor(Color.BLUE);
        bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.food_diary_row_1);
        resources = context.getResources();
        padLeft = resources.getDimension(R.dimen.size_30dip);
        padTop = resources.getDimension(R.dimen.size_3dip);
    }

Để custom 1 view thì tùy vào mục đích người ta override (ghi đè) các method có sẵn nhưng một method cực kỳ quan trọng trong kỹ thuật customview là method onDraw();

@Override
    protected void onDraw(Canvas canvas) {
        Rect r = mRect;
        Paint paint = mPaint;
        int height = getHeight();
        int line_height = getLineHeight();
        int count = height / line_height;
        if (getLineCount() > count)
            count = getLineCount();
        int baseline = getLineBounds(0, r);
        for (int i = 0; i < count; i++) {
            paint.setColor(Color.parseColor("#cbcbcb"));
            canvas.drawLine(r.left - padLeft, baseline + padTop - 2, r.right, baseline + padTop - 2,
                paint);
            canvas.drawBitmap(bitmap, r.left - padLeft, baseline - (getLineHeight() / 2) - 1,
                paint);
            baseline += getLineHeight();
            canvas.save();
        }
        super.onDraw(canvas);
        canvas.restore();
    }

Đó chúng ta chùng công cụ canvas để vẽ các line sao cho cái edittext của chúng ta giống như 1 trang vở viết hay một trang nhật ký thực sự vậy. Các line vẫn sẽ kế thừa thuộc tính của edittext khi chúng ta khai báo trong file layout xml. Xong.

4.2 Và giờ chúng ta sẽ có một view dạng như này

device-2015-11-24-125802.png

Bởi vì ở đây chúng ta sử dụng edittext để xem và sửa nội dung nhật ký luôn nên mình sẽ xây dựng trước 2 chức năng để bật/tắt chức năng sửa (có dấu nháy chuột khá khó chịu khi đọc) bằng cách:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        return isEditable();
    }

    public boolean isEditable() {
        return editable;
    }

    public void setEditable(boolean editable) {
        this.editable = editable;
    }

Và chúng ta sẽ khởi tạo thêm 1 activity dùng cho việc xem, sửa nhật ký có tên DetailActivity và thêm custom view ở trên của chúng ta vào

<view
        android:id="@+id/content"
        style="@style/diary_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.framgia.diary.customview.SecondLineEditText" />

Ngoài ra trong activity Detail bạn hãy build các chức năng view (tắt chức năng edit của edittext) và sửa, xóa nhật ký nhé:

public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.detail_menu, menu);
        updateMenu(menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_save) {
            onActionSave();
        } else if (id == R.id.action_edit) {
            onActionEdit();
        } else if (id == R.id.action_delete) {
            onActionDelete();
        }
        return true;
    }

    private void onActionDelete() {
        if (diary == null)
            return;
        diary.deleted = true;
        long deletedId = diary.save();
        if (deletedId > 0)
            finish();
        else
            showError();
    }

    private void showError() {
        final AlertDialog dialog =
            new AlertDialog.Builder(this).setTitle(getString(R.string.app_name))
                .setMessage("Error! Please contact developer to get support.\n\n")
                .setCancelable(true).setPositiveButton("OK", new OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).create();
        dialog.show();
    }

    private void onActionEdit() {
        isModeView = false;
        invalidateOptionsMenu();
    }

    private void onActionSave() {
        if (TextUtils.isEmpty(content.getText().toString()))
            return;
        if (diary == null) {
            diary = new Diary();
            diary.created_date = System.currentTimeMillis();
        }
        diary.update_date = System.currentTimeMillis();
        diary.content = content.getText().toString();
        long savedId = diary.save();
        if (savedId > 0) {
            isModeView = true;
            invalidateOptionsMenu();
        } else {
            showError();
        }
    }

Vậy là về cơ bản thì chúng ta đã xây dựng xong 1 ứng dụng nhật ký của riêng mình rồi đấy. Thật đơn giản phải không nào?

Để ứng dụng trông bắt mắt và giống một cuốn nhật ký thực hơn nữa chúng ta sẽ thêm font chữ vào nhé. Ở đây mình chọn 2 font chữ nghệ thuật là CenturyGothicAngelina Bạn có thể tham khảo project đầy đủ trên github nhé. Nào hãy vọc code và thiết kế một ứng dụng nhật ký cho riêng mình đi thôi. Link APK demo >>> DOWNLOAD

III. Kết thúc

Trong bài tới mình sẽ hướng dẫn các bạn làm NestedFragment (lồng fragment) và DrawerLayout (menu ẩn hiện theo cử chỉ vuốt màn hình qua trái hay phải màn hình của android) nhé. Xin chào và hẹn gặp lại.