2

I am currently facing an issue where I want to display a shape behind a part of text, and then a different shape behind the next part of text. I tried using multiple TextViews, but I did not know how to get them to show as if it was one text. I also tried using a SpannableString, but I couldn't make this work. To make this more clear, this is the way I want it:

My shapes are XML files, loaded as drawables.

The SpannableString code I tried is this:

SpannableString ss = new SpannableString("abc");
Drawable d1 = getResources().getDrawable(R.drawable.oval_background);
d1.setBounds(0, 0, d1.getIntrinsicWidth(), d1.getIntrinsicHeight());
ImageSpan span = new ImageSpan(d1, ImageSpan.ALIGN_BASELINE);
ss.setSpan(span, 0, 3, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
tv.setText(ss);

But neither the text nor the background showed up here. Trying another drawable makes the drawable show up, but not the text.

This is oval_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >

  <corners
    android:bottomLeftRadius="30dp"
    android:bottomRightRadius="30dp"
    android:radius="60dp"
    android:topLeftRadius="30dp"
    android:topRightRadius="30dp" />

  <solid android:color="#1287A8" />

  <padding
    android:bottom="5dp"
    android:left="10dp"
    android:right="10dp"
    android:top="5dp" />

</shape>   

Now my question is, what is the best way to get my desired result?

Edit: Using the Flexbox as @R. Zagórski suggested, I come to this result:

Which is an improvement, but it is not yet finished. The Flexbox code I am using is:

<com.google.android.flexbox.FlexboxLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:flexDirection="row"
    app:flexWrap="wrap"
    app:justifyContent="flex_start"
    app:alignItems="flex_start"
    app:alignContent="flex_start"
    android:id="@+id/flexbox"
    android:layout_marginTop="@dimen/text_margin_small"
    android:layout_marginLeft="@dimen/text_margin_small"
    android:layout_marginRight="@dimen/text_margin_small">

</com.google.android.flexbox.FlexboxLayout>
user2988879
  • 379
  • 2
  • 6
  • 18

4 Answers4

1

You can use your generated custom shapes into your textView by using background attribute. The main benefit of using custom shapes is to enhance the look by using gradient.

Steps :

  1. Create a custom shape resource layout file for your View in drawable directory.

    <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <stroke android:width="2dp" android:color="@android:color/holo_purple"/> <gradient android:angle="90" android:startColor="@color/colorPrimary" android:endColor="@android:color/holo_green_dark"/> <corners android:radius="50dp"/> <padding android:left="2dp" android:bottom="2dp" android:right="2dp" android:top="2dp"/> </shape>

  2. In the Layout file of TextView , add attribute android:background="@drawable/yourshape" :

    <TextView android:textSize="50sp" android:textColor="@android:color/white" android:gravity="center_horizontal|center_vertical" android:text="Hello World!" android:layout_width="300dp" android:layout_height="200dp" android:background="@drawable/shape1"/>

  3. This layout created following output , .

NIKUNJ KHOKHAR
  • 791
  • 6
  • 17
0

For applying background for TextView use android:background attribute like in this answer or when created programatically use setBackground method of TextView. For arranging TextViews like you shown, use FlexBoxLayout from Google: https://github.com/google/flexbox-layout

R. Zagórski
  • 20,020
  • 5
  • 65
  • 90
  • Thanks for your answer, I looked into the Flexbox you suggested. I couldn't get it entirely the way I wanted it, but it is a step in the right direction. I edited the OP. – user2988879 Jun 13 '17 at 16:24
  • Well, I don't quite understand, where the problem exactly lies. Maybe You need to measure text width to divide longer text portions into smaller ones to fit one line? https://stackoverflow.com/a/18958569/6507689 – R. Zagórski Jun 13 '17 at 16:44
0

It's ease to done without any library. Here is working example

UPDATED

  1. Define main method. Which will invoke creation View. (You can use you custom layout, or something else). And then create random shapes as background for view and color.

    /**
     * Max Width for all random text.
     * Should include margins of layout, etc.
     */
    private int getMaxWidthLine () {
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        return size.x - 20;
    }
    /**
     * Parent of all Random TextView should LinerLayout with vertical
     * orientation, to apply building Views line by line, based on Width.
     */
    private void addRandomTextInLine (LinearLayout mainViewGroup, TextView textView) {
        LinearLayout lastTextHolder;
        if (mainViewGroup.getChildCount() > 0) {
            lastTextHolder = (LinearLayout) mainViewGroup.
                    getChildAt(mainViewGroup.getChildCount() - 1);
        } else {
            LinearLayout firstTextHolder = new LinearLayout(MainActivity.this);
            firstTextHolder.setLayoutParams(new ActionBar.LayoutParams
                    (ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            firstTextHolder.addView(textView);
            mainViewGroup.addView(firstTextHolder);
            return;
        }
        mainViewGroup.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        lastTextHolder.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        textView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
    
        int maxParentWidth = getMaxWidthLine();
        int lastHolderWidth = lastTextHolder.getMeasuredWidth();
        int nextTextWidth = textView.getMeasuredWidth();
    
        if (maxParentWidth - lastHolderWidth >= nextTextWidth ) {
            lastTextHolder.addView(textView);
        } else {
            LinearLayout newTextHolder = new LinearLayout(MainActivity.this);
            newTextHolder.setLayoutParams(new ActionBar.LayoutParams
                    (ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            newTextHolder.addView(textView);
            mainViewGroup.addView(newTextHolder);
        }
    }
    
    /**
     * Start method, for generation TextView with Random Background
     */
    @SuppressWarnings("deprecation")
    private void addRandomCornersText (ViewGroup group, String text) {
        /*
         * Just defining View programmatically.
         * You can use inflate from layout.
         */
        TextView itemText = new TextView(MainActivity.this);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams
                (ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        float scale = getResources().getDisplayMetrics().density;
        int margins  = (int) (5 * scale + 0.5f);
        int padding = (int) (10 * scale + 0.5f);
        params.setMargins(margins, margins, margins, margins);
        itemText.setPadding(padding, padding, padding, padding);
        itemText.setLayoutParams(params);
    
        /*
         * Generate random shapes/corners and
         * applying this changes to the view
         */
        Random random = new Random();
        int r = random.nextInt(100);
        float[] outerR = new float[] {r, r, r, r, r, r, r, r};
        ShapeDrawable shape = new ShapeDrawable(new RoundRectShape(outerR, null, null));
        shape.getPaint().setColor(Color.argb(255, random.nextInt(256),
                random.nextInt(256), random.nextInt(256)));
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            itemText.setBackground(shape);
        } else {
            itemText.setBackgroundDrawable(shape);
        }
        itemText.setText(text);
        addRandomTextInLine((LinearLayout) group, itemText);
    }
    

    }

  2. Call, wherever you need your method. Which wil return random color and shapes TextView.

    ViewGroup viewGroup = (ViewGroup) findViewById(R.id.main_text_holder);
    for (int i = 0; i < 15; i++) {
        addRandomCornersText(viewGroup, LoremIpsum.getInstance().getWords(1, 4));
    }
    

Than you will se something like below. But there also some additional impromevents, like adding invert color for TextView Text Color, some Width Settings, etc.

EXAMPLES

GensaGames
  • 5,538
  • 4
  • 24
  • 53
  • Hey, thanks alot for taking the time to write this. I had something similar, but the issue I have is that if a TextView does not fill up the full width, a new one does not start. This is what I'm trying to accomplish. Once the complete width is taken up, the TextView should continue on the next line. – user2988879 Jun 13 '17 at 17:37
  • @user2988879 But what is the problem? Calculate screen width, and split to new Liner Layout if with is more then expected? Is it problem? – GensaGames Jun 13 '17 at 20:00
0

you can use android custom button generator, set backgrounds to buttons as per your choice