Wednesday 14 February 2018

HB Blog 152: ShapeLetter View In Android.

Google has been very much serious about UI and UX of an Android applications. Not only for developers but also in their own applications. Lets say Gmail, a simple mailing application but, have you observed delete and archive actions with a simple swipe and many more.

Today, we have very minute thing to do as a tutorial. When we have list of mails we have letter/text as an image for representing the user's profile. Let us see how it is done in below sample code.
Refer the below link for complete sample code:-

Download Sample Code

Have a look on few code snippets,

//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
<?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:orientation="vertical"
    android:layout_height="match_parent">

    <com.harshalbenake.shapeletter.views.ShapeLetter
        app:letter="H"
        app:letter_color="@android:color/white"
        app:shape="rect"
        app:letter_size="16dp"
        app:shape_color="@android:color/holo_red_dark"
        android:layout_margin="16dp"
        android:layout_gravity=""
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


    <com.harshalbenake.shapeletter.views.ShapeLetter
        app:letter="B"
        android:layout_margin="16dp"
        app:letter_size="16dp"
        app:letter_color="@android:color/white"
        app:shape="oval"
        app:shape_color="@android:color/holo_blue_dark"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

//ShapeLetter.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
192
193
package com.harshalbenake.shapeletter.views;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;

import com.harshalbenake.shapeletter.R;

public class ShapeLetter extends View {


    private static int SHAPE_OVAL=1;
    private static int SHAPE_RECT=2;
    private static int DEFAULT_LETTER_COLOR = Color.WHITE;
    private static int DEFAULT_SHAPE_COLOR = Color.CYAN;
    private static final int DEFAULT_VIEW_SIZE = 96;
    private static float DEFAULT_LETTER_SIZE = 25f;
    private static String DEFAULT_LETTER = "A";
    private static final int DEFAULT_SHAPE=SHAPE_OVAL;

    private int mTitleColor = DEFAULT_LETTER_COLOR;
    private int mBackgroundColor = DEFAULT_SHAPE_COLOR;
    private String mTitleText = DEFAULT_LETTER;
    private float mTitleSize = DEFAULT_LETTER_SIZE;
    private int mShape=DEFAULT_SHAPE;

    private TextPaint mTitleTextPaint;
    private Paint mBackgroundPaint;
    private RectF mInnerRectF;
    private int mViewSize;

    private Typeface mFont = Typeface.defaultFromStyle(Typeface.NORMAL);

    public ShapeLetter(Context context) {
        super(context);
        init(null, 0);
    }

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

    public ShapeLetter(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle);
    }

    private void init(AttributeSet attrs, int defStyle) {
        final TypedArray a = getContext().obtainStyledAttributes(
                attrs, R.styleable.ShapeLetter, defStyle, 0);

        if(a.hasValue(R.styleable.ShapeLetter_letter)){
            mTitleText = a.getString(R.styleable.ShapeLetter_letter);
        }

        mShape = a.getInteger(R.styleable.ShapeLetter_shape,DEFAULT_SHAPE);


        mTitleColor = a.getColor(R.styleable.ShapeLetter_letter_color, DEFAULT_LETTER_COLOR);
        mBackgroundColor = a.getColor(R.styleable.ShapeLetter_shape_color, DEFAULT_SHAPE_COLOR);
        mTitleSize = a.getDimension(R.styleable.ShapeLetter_letter_size, DEFAULT_LETTER_SIZE);
        a.recycle();

        //Title TextPaint
        mTitleTextPaint = new TextPaint();
        mTitleTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mTitleTextPaint.setTypeface(mFont);
        mTitleTextPaint.setTextAlign(Paint.Align.CENTER);
        mTitleTextPaint.setLinearText(true);
        mTitleTextPaint.setColor(mTitleColor);
        mTitleTextPaint.setTextSize(mTitleSize);

        //Background Paint
        mBackgroundPaint = new Paint();
        mBackgroundPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mBackgroundPaint.setStyle(Paint.Style.FILL);
        mBackgroundPaint.setColor(mBackgroundColor);

        mInnerRectF = new RectF();
    }

    private void invalidateTextPaints(){
        mTitleTextPaint.setTypeface(mFont);
        mTitleTextPaint.setTextSize(mTitleSize);
    }

    private void invalidatePaints(){
        mBackgroundPaint.setColor(mBackgroundColor);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = resolveSize(DEFAULT_VIEW_SIZE, widthMeasureSpec);
        int height = resolveSize(DEFAULT_VIEW_SIZE, heightMeasureSpec);
        mViewSize = Math.min(width, height);

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        mInnerRectF.set(0, 0, mViewSize, mViewSize);
        mInnerRectF.offset((getWidth() - mViewSize) / 2, (getHeight() - mViewSize) / 2);

        float centerX = mInnerRectF.centerX();
        float centerY = mInnerRectF.centerY();

        int xPos = (int) centerX;
        int yPos = (int) (centerY - (mTitleTextPaint.descent() + mTitleTextPaint.ascent()) / 2);
        if(mShape==SHAPE_OVAL)
        {
            canvas.drawOval(mInnerRectF, mBackgroundPaint);
        }
        else if(mShape==SHAPE_RECT){
            canvas.drawRect(mInnerRectF, mBackgroundPaint);
        }
        canvas.drawText(mTitleText,
                xPos,
                yPos,
                mTitleTextPaint);
    }

    /**
     * Gets the title string attribute value.
     * @return The title string attribute value.
     */
    public String getTitleText() {
        return mTitleText;
    }

    /**
     * Sets the view's title string attribute value.
     * @param title The example string attribute value to use.
     */
    public void setTitleText(String title) {
        mTitleText = title;
        invalidate();
    }

    /**
     * Gets the background color attribute value.
     * @return The background color attribute value.
     */
    public int getBackgroundColor() {
        return mBackgroundColor;
    }

    /**
     * Sets the view's background color attribute value.
     * @param backgroundColor The background color attribute value to use.
     */
    public void setBackgroundColor(int backgroundColor) {
        mBackgroundColor = backgroundColor;
        invalidatePaints();
    }

    /**
     * Gets the title size dimension attribute value.
     * @return The title size dimension attribute value.
     */
    public float getTitleSize() {
        return mTitleSize;
    }

    /**
     * Sets the view's title size dimension attribute value.
     * @param titleSize The title size dimension attribute value to use.
     */
    public void setTitleSize(float titleSize) {
        mTitleSize = titleSize;
        invalidateTextPaints();
    }

    /**
     * Sets the view's title typeface.
     * @param font The typeface to be used for the text.
     */
    public void setTextTypeface(Typeface font){
        this.mFont = font;
        invalidateTextPaints();
    }
}