Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Align 2 texts, 1 normal, 1 opposite

I make a android application with a button where in there a total of 4 texts and I want to align the first 2. One at the most left side of the bottom text and the other and the right side of the bottom text.

So from this:

Before

setText(item.title + " " + item.roomId + "\n" + item.teacher + " " + item.classes);

To this:

After (this is what I want)

setText(declare here a spannable);

I think I should work with Spannable, I've tried some things with Alignment.ALIGN_NORMAL and Alignment.ALIGN_OPPOSITE but I think is should first calculate the length of the bottom text and then do the alignment. (I've found a good example here but it's not working in my set-up).

I hope that someone can point me to a good direction.

Edit:

The reason that I can not (I think) use RelativeLayout or LinearLayout is that I'm extending button in a different class (ScheduleItemView.java):

/**
 * Custom view that represents a {@link ScheduleItem} instance, including its
 * title and time span that it occupies. Usually organized automatically by
 * {@link ScheduleItemsLayout} to match up against a {@link TimeRulerView}
 * instance.
 */
public class ScheduleItemView extends Button {

    private ScheduleItem mItem;

    public ScheduleItemView(Context context, ScheduleItem item) {
        super(context);

        mItem = item;

        setSingleLine(false);
        setText(item.title + " " + item.roomId + "\n" + item.teacher + " "
                + item.classes);

        // TODO: turn into color state list with layers?
        int textColor = Color.WHITE;
        int accentColor = item.accentColor;

        LayerDrawable buttonDrawable = (LayerDrawable) context.getResources()
                .getDrawable(R.drawable.btn_block);
        buttonDrawable.getDrawable(0).setColorFilter(accentColor,
                PorterDuff.Mode.SRC_ATOP);
        buttonDrawable.getDrawable(1).setAlpha(item.containsStarred ? 255 : 0);

        setTextColor(textColor);
        setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
                .getDimensionPixelSize(R.dimen.text_size_small));

        setGravity(Gravity.CENTER | Gravity.BOTTOM);

        setBackgroundDrawable(buttonDrawable);
    }

    public ScheduleItem getScheduleItem() {
        return mItem;
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                getMeasuredHeight(), MeasureSpec.EXACTLY));
        // layout(getLeft(), getTop(), getRight(), getBottom());
        setGravity(Gravity.CENTER);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getRight() - getLeft(), getBottom() - getTop());
    }
}

I've tried to do this in protected void onLayout (ScheduleItemsLayout.java):

child.setLayoutParams(new LayoutParams(
        LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

But that's not working. I'm not sure if I should use new RelativeLayout(this).

Is it better to use Spannable in this case?

The source of the project can be downloaded here (which you can import in Eclipse)

like image 557
user2784435 Avatar asked Nov 25 '13 12:11

user2784435


1 Answers

Well, if you can't make the move from Button to a ViewGroup, here's what you can do in your extended Button class:

Remove:

setText(item.title + " " + item.roomId + "\n" + item.teacher + " "
            + item.classes);

Add the following to ScheduleItemView's constructor:

float[] fl1 = new float[item.title.length()];
getPaint().getTextWidths(item.title, fl1);

float[] fl2 = new float[item.roomId.length()];
getPaint().getTextWidths(item.roomId, fl2);

float[] fl3 = new float[item.teacher.length() + item.classes.length() + 1];
getPaint().getTextWidths(item.teacher + " " + item.classes, fl3);

float differenceInWidth = sumUpTheArray(fl3) 
                          - sumUpTheArray(fl1) 
                          - sumUpTheArray(fl2);

float fSpaceArray[] = new float[1];

getPaint().getTextWidths(" ", fSpaceArray);

int numOfSpaces = (int) (differenceInWidth / fSpaceArray[0]);

char[] spaceCharArr = new char[numOfSpaces];

Arrays.fill(spaceCharArr, ' ');

setText(item.title + String.valueOf(spaceCharArr) + item.roomId + "\n" 
                            + item.teacher + " " + item.classes);

Add this helper method which sums up a float array:

public float sumUpTheArray(float[] arr) {
    float sum = 0f;

    for (int i = 0; i < arr.length; i++) {
        sum += arr[i];
    }

    return sum;
}

Not sure why you're overriding the onDraw(Canvas) and onMeasure(int, int) methods.

Needless to say, this is one convoluted code snippet. What's happening is that we're measuring how much space we must put between title and roomId to get the desired alignment. The code is straight-forward (though cringe-worthy), so no comments have been included.

On the other hand, you could extend RelativeLayout:

public class ScheduleItemAlternateView extends RelativeLayout {

    private ScheduleItem mItem;  

    public ScheduleItemAlternateView(Context context, ScheduleItem item) {
        super(context);

        mItem = item;

        int textColor = Color.WHITE;
        int accentColor = item.accentColor;

        LayerDrawable buttonDrawable = (LayerDrawable) context.getResources()
            .getDrawable(R.drawable.btn_block);
        buttonDrawable.getDrawable(0).setColorFilter(accentColor,
            PorterDuff.Mode.SRC_ATOP);
        buttonDrawable.getDrawable(1).setAlpha(item.containsStarred ? 255 : 0);

        // Three TextViews to hold the `title`, `roomId`
        // and `teacher&room` independently
        TextView tvTitle = new TextView(context);
        TextView tvRoomId = new TextView(context);
        TextView tvTeacherAndClasses = new TextView(context);

        // Example ids
        tvTitle.setId(100);
        tvRoomId.setId(101);
        tvTeacherAndClasses.setId(102);

        tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
            .getDimensionPixelSize(R.dimen.text_size_small));
        tvRoomId.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
            .getDimensionPixelSize(R.dimen.text_size_small));
        tvTeacherAndClasses.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources()
            .getDimensionPixelSize(R.dimen.text_size_small));

        tvTitle.setPadding(30, 20, 30, 0);
        tvRoomId.setPadding(30, 20, 30, 0);
        tvTeacherAndClasses.setPadding(30, 5, 30, 20);

        tvTitle.setTextColor(textColor);
        tvRoomId.setTextColor(textColor);
        tvTeacherAndClasses.setTextColor(textColor);

        // Set text
        tvTitle.setText(item.title);        
        tvRoomId.setText(item.roomId);      
        tvTeacherAndClasses.setText(item.teacher + " " + item.classes);

        // LayoutParms
        RelativeLayout.LayoutParams paramsTitle = 
                                 new RelativeLayout.LayoutParams(
                                     RelativeLayout.LayoutParams.WRAP_CONTENT,
                                     RelativeLayout.LayoutParams.WRAP_CONTENT);

        paramsTitle.addRule(RelativeLayout.ALIGN_LEFT, 
                                                  tvTeacherAndClasses.getId());

        RelativeLayout.LayoutParams paramsRoomId = 
                                 new RelativeLayout.LayoutParams(
                                     RelativeLayout.LayoutParams.WRAP_CONTENT,
                                     RelativeLayout.LayoutParams.WRAP_CONTENT);

        paramsRoomId.addRule(RelativeLayout.ALIGN_RIGHT, 
                                                  tvTeacherAndClasses.getId());

        RelativeLayout.LayoutParams paramsTeacherAndClasses = 
                                 new RelativeLayout.LayoutParams(
                                     RelativeLayout.LayoutParams.WRAP_CONTENT,
                                     RelativeLayout.LayoutParams.WRAP_CONTENT);

        paramsTeacherAndClasses.addRule(RelativeLayout.CENTER_HORIZONTAL);
        paramsTeacherAndClasses.addRule(RelativeLayout.BELOW, tvTitle.getId());

        // Add Views to this RelativeLayout
        addView(tvTitle, paramsTitle);
        addView(tvRoomId, paramsRoomId);
        addView(tvTeacherAndClasses, paramsTeacherAndClasses);

        // Set the background as LayerDrawable
        setBackgroundDrawable(buttonDrawable);          
    }
}

Here, we create three TextViews, and set their LayoutParams to get proper alignment.

Output is the same for both, though I would recommend the second approach:

enter image description here

like image 114
Vikram Avatar answered Sep 27 '22 03:09

Vikram