Quantcast
Channel: Ixtendo » Java
Viewing all articles
Browse latest Browse all 2

How to Add a Caption Text over an Image in Android

$
0
0

In this article, I will explain how you can add a caption text over the bottom of an image in Android.

The Layout Design

To add a caption over an image, I will use a relative layout that will include an ImageView and two TextView’s (in Android, the RelativeLayout allows you to overlap multiple views). I will use this image as a test image (I copied it to the res/drawable folder under the name of house.jpg):

house-demo

First, we must create an activity demo class like this:

package com.ixtendo.captionimg;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class ImageCaptionActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_caption);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_image_caption, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

The activity_image_caption.xml (it can be found in the res/layout folder. If you don’t find it, then you can create it.) activity will look like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/relativeLayout">

    <ImageView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/imageView"
        android:layout_alignParentBottom="true"
        android:src="@drawable/house"
        android:adjustViewBounds="true" />

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginRight="5dp"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="5dp">

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="Caption Title"
            android:id="@+id/captionTitleView" />

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            android:id="@+id/captionTextView" />

    </LinearLayout>

</RelativeLayout>

If you run your small application, you will see a screen like this:

android-house-demo-without-gradient

 

As you can see, the caption is not visible. To make it visible, we need to change the color of the caption text and add a black gradient over the bottom of the picture.

Draw a Gradient over the Image

To make the caption always visible, we need to make the following changes:

  1. Change the color of the caption text to white.
  2. Add a black gradient over the bottom of the image.

To add an unobtrusive gradient over the bottom of the image, I created the following class:

package com.ixtendo.captionimg;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;

import java.io.InputStream;

public class GradientOverImageDrawable extends BitmapDrawable {

    private int[] gradientColors;
    private float[] gradientPositions;
    private double gradientStart = 0.55;
    private double gradientEnd = 1;

    public GradientOverImageDrawable(Resources res, Bitmap bitmap) {
        super(res, bitmap);
    }

    public GradientOverImageDrawable(Resources res, String filepath) {
        super(res, filepath);
    }

    public GradientOverImageDrawable(Resources res, InputStream is) {
        super(res, is);
    }

    public void setGradientColors(int[] gradientColors) {
        this.gradientColors = gradientColors;
    }

    public void setGradientColors(int startColor, int... endColors) {
        if (endColors.length == 0) {
            throw new IllegalArgumentException("The endColors array must have at least one element");
        }
        gradientColors = new int[endColors.length + 1];
        gradientColors[0] = startColor;
        System.arraycopy(endColors, 0, gradientColors, 1, endColors.length);
    }

    public int[] getGradientColors() {
        return gradientColors;
    }

    public float[] getGradientPositions() {
        return gradientPositions;
    }

    public void setGradientPositions(float[] gradientPositions) {
        for (float pos : gradientPositions) {
            if (pos > 1 || pos < 0) {
                throw new IllegalArgumentException("The gradient position must be a float number between 0 and 1");
            }
        }
        this.gradientPositions = gradientPositions;
    }

    public double getGradientStart() {
        return gradientStart;
    }

    public void setGradientStart(double gradientStart) {
        this.gradientStart = gradientStart;
    }

    public double getGradientEnd() {
        return gradientEnd;
    }

    public void setGradientEnd(double gradientEnd) {
        this.gradientEnd = gradientEnd;
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        if (gradientColors != null) {
            Rect bounds = getBounds();

            int x0 = bounds.left;
            int y0 = (int) Math.round(bounds.bottom * gradientStart);
            int x1 = x0;
            int y1 = (int) Math.round(bounds.bottom * gradientEnd);

            LinearGradient shader = new LinearGradient(x0, y0, x1, y1, gradientColors, gradientPositions, Shader.TileMode.CLAMP);
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setShader(shader);
            canvas.drawRect(x0, y0, bounds.right, y1, paint);
        }
    }
}

Below you can find a short description of this class’ parameters:

  • gradientColors – the colors to be distributed along the gradient line
  • gradientPositions – the relative positions [0…1] of each corresponding color in the colors array
  • gradientStart – the linear gradient start position. The default value is 0.55 (the gradient starts at 55% of the image height)
  • gradientEnd – the linear gradient end position. The default value is 1 (the gradient will end at the bottom of the image)

Next, I will update the onCreate method in the ImageCaptionActivity class like this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_image_caption);

    TextView captionTitle = (TextView) findViewById(R.id.captionTitleView);
    TextView captionBody = (TextView) findViewById(R.id.captionTextView);
    ImageView imageView = (ImageView) findViewById(R.id.imageView);

    captionTitle.setTextColor(Color.WHITE);
    captionBody.setTextColor(Color.WHITE);

    Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.house);
    int gradientStartColor = Color.argb(0, 0, 0, 0);
    int gradientEndColor = Color.argb(255, 0, 0, 0);
    GradientOverImageDrawable gradientDrawable = new GradientOverImageDrawable(getResources(), image);
    gradientDrawable.setGradientColors(gradientStartColor, gradientEndColor);

    imageView.setImageDrawable(gradientDrawable);
}

In this method, I made the following modifications:

  • I searched the caption text views and set the white text color.
  • I loaded the image resource from the disc as Bitmap using the BitmapFactory class.
  • I defined the gradient start and end colors like this:
    • start color = Color.argb(0, 0, 0, 0) – black color with full transparency
    • end color = Color.argb(255, 0, 0, 0) – black color without transparency (a 255 value for the first argument of the Color.argb method means no transparency)
  • I created a new instance of the GradientOverImageDrawable class by passing the loaded image to it.
  • I set the new ImageDrawable instance on image view.

If you launch the Android Simulator again, the following image will be displayed:

android-house-demo-with-gradient

Integration with Other Libraries

Recently, I used the Android Universal Image Loader library to optimize the image loading in my project. If you want to add a gradient over the images loaded by this library, you must do it in this way:

ImageView imageView = (ImageView) findViewById(...);
DisplayImageOptions dio = new DisplayImageOptions.Builder().displayer(new BitmapDisplayer() {
    @Override
    public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
        int gradientStartColor = Color.argb(0, 0, 0, 0);
        int gradientEndColor = Color.argb(255, 0, 0, 0);
        GradientOverImageDrawable gradientDrawable = new GradientOverImageDrawable(getResources(), bitmap);
        gradientDrawable.setGradientColors(gradientStartColor, gradientEndColor);
        imageAware.setImageDrawable(gradientDrawable);
    }
}).build();
ImageLoader.getInstance().displayImage("Your image URL", imageView, dio);

Conclusions

As we can see, adding a caption over an image in Android is not difficult. There are also other ways of adding gradients in Android using the XML method, but I didn’t obtain the same result as the one using the method described in this article.


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images