Position children views relative to their parent view - android

I need to implement a view that looks like this
The hard part is that the sizes and the font sizes of the textviews need to be adaptable to the width and height of the parent view. Here is what I have tried and the result is
The xml file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_width="200dp"
tools:layout_height="100dp"
android:orientation="vertical">
<BuySellView
android:id="#+id/tradeNow_layoutSell"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="#color/gray_light_light">
<LinearLayout
android:id="#+id/smallPart1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top|right"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical">
<ImageView
android:id="#+id/greenArrowSellImg"
android:layout_width="10dp"
android:layout_height="10dp"
android:src="#drawable/green_arrow"
android:visibility="invisible"
tools:visibility="visible" />
<ImageView
android:id="#+id/redArrowSellImg"
android:layout_width="10dp"
android:layout_height="10dp"
android:src="#drawable/red_arrow"
android:visibility="invisible"
tools:visibility="visible" />
</RelativeLayout>
<TextView
android:id="#+id/smallPart1Txt"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="top|right"
android:layout_gravity="center_vertical"
android:maxLines="1"
android:text="#string/misc_blank"
android:textColor="#android:color/black"
tools:text="10,015." />
</LinearLayout>
<TextView
android:id="#+id/largePart"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxLines="1"
android:text="#string/misc_blank"
android:textColor="#android:color/black"
tools:text="46"
android:gravity="center"
tools:textColor="#color/red_sell" />
<TextView
android:id="#+id/smallPart2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:maxLines="1"
android:text="#string/misc_blank"
android:textColor="#android:color/black"
android:gravity="left|center_vertical"
tools:text="8"
tools:textColor="#color/red_sell" />
<TextView
android:id="#+id/trdLbl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#drawable/rounded_corner_sell"
android:text="#string/CommonCapitalSell"
android:textColor="#color/white" />
</BuySellView>
</LinearLayout>
The custom view:
public class BuySellView extends ViewGroup {
private final Rect mTmpChildRect = new Rect();
public BuySellView(Context context) {
super(context);
}
public BuySellView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BuySellView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int t = 10;
int b = 10 + height / 3 * 2;
LinearLayout smallPart1 = (LinearLayout) findViewById(R.id.smallPart1);
smallPart1.layout(0, height / 3, width / 2, b);
smallPart1.setGravity(Gravity.RIGHT);
TextView smallPart1Txt = (TextView) smallPart1.findViewById(R.id.smallPart1Txt);
smallPart1Txt.setTextSize(height / 4 / 2);
TextView largePart = (TextView) findViewById(R.id.largePart);
largePart.setTextSize(height / 3);
largePart.layout(width / 2, 10, b - t + width / 2, b);
TextView smallPart2 = (TextView) findViewById(R.id.smallPart2);
smallPart2.layout(b - t + width / 2, t, width, height / 2);
smallPart2.setTextSize(height / 4 / 2);
TextView tradeLbl = (TextView) findViewById(R.id.trdLbl);
tradeLbl.layout(width / 2 - width / 3 / 2, height / 4 * 3 + 10, width / 2 + width / 3 / 2, height / 4 * 4 + 10);
tradeLbl.setGravity(Gravity.CENTER);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
LinearLayout smallPart1 = (LinearLayout) findViewById(R.id.smallPart1);
TextView largePart = (TextView) findViewById(R.id.largePart);
TextView smallPart2 = (TextView) findViewById(R.id.smallPart2);
TextView tradeLbl = (TextView) findViewById(R.id.trdLbl);
smallPart1.measure(Math.max(smallPart1.getMeasuredWidth(), widthMeasureSpec / 8 * 3), heightMeasureSpec / 4);
largePart.measure(heightMeasureSpec / 4 * 2, heightMeasureSpec / 4 * 2);
smallPart2.measure(Math.max(smallPart2.getMeasuredWidth(), widthMeasureSpec / 8), smallPart2.getMeasuredHeight());
tradeLbl.measure(widthMeasureSpec / 3, heightMeasureSpec / 4);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
#Override
public boolean shouldDelayChildPressedState() {
return false;
}
}

try this XML:
<RelativeLayout
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0.87"
android:textSize="25sp"
android:layout_alignBottom="#+id/large"
android:paddingBottom="8dp"
android:fontFamily="sans-serif-light"
/>
<TextView
android:id="#+id/large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/small"
android:text="46"
android:textSize="58sp"
android:textColor="#00DC00"
android:fontFamily="sans-serif-light"
/>
<TextView
android:id="#+id/up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="9"
android:textSize="24sp"
android:layout_alignTop="#+id/large"
android:layout_toRightOf="#+id/large"
android:textColor="#00DC00"
android:fontFamily="sans-serif-light"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="30dp"
android:background="#FF4848"
android:layout_below="#+id/large"
android:layout_alignRight="#+id/large"
android:text="Sell USD"
android:padding="5dp"
android:textColor="#fff"
android:textSize="12sp"
/>
</RelativeLayout>
You can change the textSize based on number of character or width of text via java code.

Related

How to delete Additional space ImageView in Android

I want use ImageView in my project, but it shows additional space in the layout. How can I remove the additional space?
This image shows the problem:
XML code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.tellfa.smsbox.activities.Dialog_image_show">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:src="#drawable/cover_menu_bg" />
</RelativeLayout>
</RelativeLayout>
I don't want use android:scaleType="centerCrop".
Use the imageview like these
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="#drawable/icon"
android:id="#+id/imv"
android:scaleType="fitCenter" />
Try this custom ImageView class
public class ResizableImageView extends ImageView {
public ResizableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
Drawable d = getDrawable();
if(d!=null){
// ceil not round - avoid thin vertical gaps along the left/right edges
int width = View.MeasureSpec.getSize(widthMeasureSpec);
int height = (int) Math.ceil((float) width * (float) d.getIntrinsicHeight() / (float) d.getIntrinsicWidth());
setMeasuredDimension(width, height);
}else{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
And use this class as below
<your_package.ResizableImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:src="#drawable/cover_menu_bg" />
For anyone looking for solution for both orientations. Here is my approach with samples:
First, my xml:
<?xml version="1.0" encoding="utf-8"?>
<com.example.michal.fillimageview.CustomLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#f0f000"
android:orientation="vertical">
<com.example.michal.fillimageview.ResizableImageView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:src="#drawable/p600_900" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/background_dark"
android:text="Hello World!"
android:textColor="#android:color/holo_red_dark"
android:textSize="30sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/background_dark"
android:text="Hello World!"
android:textColor="#android:color/holo_red_dark"
android:textSize="30sp" />
</com.example.michal.fillimageview.CustomLinearLayout>
Class:
public class ResizableImageView extends ImageView {
public ResizableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Drawable d = getDrawable();
if (d != null) {
// ceil not round - avoid thin vertical gaps along the left/right edges
int width = View.MeasureSpec.getSize(widthMeasureSpec);
int height = View.MeasureSpec.getSize(heightMeasureSpec);
if (height > width) {//portrait
if (d.getIntrinsicWidth() > d.getIntrinsicHeight()) {
height = (int) Math.ceil((float) width * (float) d.getIntrinsicHeight() / (float) d.getIntrinsicWidth());
setMeasuredDimension(width, height);
} else {
width = (int) Math.ceil((float) height * (float) d.getIntrinsicWidth() / (float) d.getIntrinsicHeight());
setMeasuredDimension(width, height);
}
} else {//landscape
width = (int) Math.ceil((float) height * (float) d.getIntrinsicWidth() / (float) d.getIntrinsicHeight());
setMeasuredDimension(width, height);
}
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
Samples for specific images:
600x900 portrait
600x900 landscape
800x600 portrait
800x600 landscape

Whatsapp Message Layout - How to get time-view in the same row

I was wondering how WhatsApp handles the time shown in every message.
For those who don't know:
If the message is very short, the text and time are in the same row.
If the message is long, the time is in the bottom right corner - the text wrapped around it.
With a RelativeLayout and toLeftOf I would get 1) but not 2) as previous lines would be "cut off" at the position of the time view. Same behaviour If i use a LinearLayout.
So I tried to use a FrameLayout or a RelativeLayout without any connection between text and time.
However, if the text is as long as the message-view is big, both views would overlap.
If I put blank characters to my message I wouldn't have the time on the right.
Do they really have some kind of text-wrapping-lib for this or is it possible to do only with layouts?
Here is the requested screenshot:
#Hisham Muneer 's answer very good.
But there are some problems. For example:
If the TextView has 2 full lines (end to end), the text will
intersect with datetime text layout. Finally, the views will
look like onion effect.
The text line wraps can't works efficiently. You must control this
lines and relocate the datetime view.
I'm going to share my solution, if you will need like this problem.
This is example screenshot
ImFlexboxLayout.java
public class ImFlexboxLayout extends RelativeLayout {
private TextView viewPartMain;
private View viewPartSlave;
private TypedArray a;
private RelativeLayout.LayoutParams viewPartMainLayoutParams;
private int viewPartMainWidth;
private int viewPartMainHeight;
private RelativeLayout.LayoutParams viewPartSlaveLayoutParams;
private int viewPartSlaveWidth;
private int viewPartSlaveHeight;
public ImFlexboxLayout(Context context) {
super(context);
}
public ImFlexboxLayout(Context context, AttributeSet attrs) {
super(context, attrs);
a = context.obtainStyledAttributes(attrs, R.styleable.ImFlexboxLayout, 0, 0);
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
try {
viewPartMain = (TextView) this.findViewById(a.getResourceId(R.styleable.ImFlexboxLayout_viewPartMain, -1));
viewPartSlave = this.findViewById(a.getResourceId(R.styleable.ImFlexboxLayout_viewPartSlave, -1));
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (viewPartMain == null || viewPartSlave == null || widthSize <= 0) {
return;
}
int availableWidth = widthSize - getPaddingLeft() - getPaddingRight();
int availableHeight = heightSize - getPaddingTop() - getPaddingBottom();
viewPartMainLayoutParams = (LayoutParams) viewPartMain.getLayoutParams();
viewPartMainWidth = viewPartMain.getMeasuredWidth() + viewPartMainLayoutParams.leftMargin + viewPartMainLayoutParams.rightMargin;
viewPartMainHeight = viewPartMain.getMeasuredHeight() + viewPartMainLayoutParams.topMargin + viewPartMainLayoutParams.bottomMargin;
viewPartSlaveLayoutParams = (LayoutParams) viewPartSlave.getLayoutParams();
viewPartSlaveWidth = viewPartSlave.getMeasuredWidth() + viewPartSlaveLayoutParams.leftMargin + viewPartSlaveLayoutParams.rightMargin;
viewPartSlaveHeight = viewPartSlave.getMeasuredHeight() + viewPartSlaveLayoutParams.topMargin + viewPartSlaveLayoutParams.bottomMargin;
int viewPartMainLineCount = viewPartMain.getLineCount();
float viewPartMainLastLineWitdh = viewPartMainLineCount > 0 ? viewPartMain.getLayout().getLineWidth(viewPartMainLineCount - 1) : 0;
widthSize = getPaddingLeft() + getPaddingRight();
heightSize = getPaddingTop() + getPaddingBottom();
if (viewPartMainLineCount > 1 && !(viewPartMainLastLineWitdh + viewPartSlaveWidth >= viewPartMain.getMeasuredWidth())) {
widthSize += viewPartMainWidth;
heightSize += viewPartMainHeight;
} else if (viewPartMainLineCount > 1 && (viewPartMainLastLineWitdh + viewPartSlaveWidth >= availableWidth)) {
widthSize += viewPartMainWidth;
heightSize += viewPartMainHeight + viewPartSlaveHeight;
} else if (viewPartMainLineCount == 1 && (viewPartMainWidth + viewPartSlaveWidth >= availableWidth)) {
widthSize += viewPartMain.getMeasuredWidth();
heightSize += viewPartMainHeight + viewPartSlaveHeight;
} else {
widthSize += viewPartMainWidth + viewPartSlaveWidth;
heightSize += viewPartMainHeight;
}
this.setMeasuredDimension(widthSize, heightSize);
super.onMeasure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY));
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (viewPartMain == null || viewPartSlave == null) {
return;
}
viewPartMain.layout(
getPaddingLeft(),
getPaddingTop(),
viewPartMain.getWidth() + getPaddingLeft(),
viewPartMain.getHeight() + getPaddingTop());
viewPartSlave.layout(
right - left - viewPartSlaveWidth - getPaddingRight(),
bottom - top - getPaddingBottom() - viewPartSlaveHeight,
right - left - getPaddingRight(),
bottom - top - getPaddingBottom());
}
}
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ImFlexboxLayout">
<attr name="viewPartMain" format="reference"></attr>
<attr name="viewPartSlave" format="reference"></attr>
</declare-styleable>
</resources>
Example right ballon layout (balloon.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="right|center_vertical"
android:layout_weight="1"
android:gravity="right">
<tr.com.client.ImFlexboxLayout
android:id="#+id/msg_layout"
style="#style/BalloonMessageLayoutRight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:gravity="left|center_vertical"
app:viewPartMain="#+id/chat_msg"
app:viewPartSlave="#+id/lytStatusContainer">
<TextView
android:id="#+id/chat_msg"
style="#style/BalloonMessageRightTextItem"
android:layout_width="wrap_content"
android:layout_gravity="right|bottom"
android:focusableInTouchMode="false"
android:gravity="left|top"
android:text="hjjfg" />
<LinearLayout
android:id="#+id/lytStatusContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:gravity="right"
android:minWidth="60dp">
<TextView
android:id="#+id/date_view"
style="#style/BallonMessageTimeText"
android:layout_alignParentRight="true"
android:layout_gravity="right|bottom"
android:layout_marginRight="5dp"
android:gravity="right"
android:maxLines="1" />
<include
android:id="#+id/lytStatus"
layout="#layout/layout_im_message_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginRight="5dp"
android:minWidth="40dp" />
</LinearLayout>
</tr.com.client.ImFlexboxLayout>
</LinearLayout>
</LinearLayout>
You can modify layout xml and some sections related your scenario.
There are 2 important point: you must define in layout xml "viewPartMain", "viewPartSlave" attributes. Because the code will decide measure via your main(chat textview) and slave(datetime text view) elements.
I wish have good days. Greets.
Adding HTML non-breaking spaces did the trick. Tested the code on most devices and working absolutely fine. Maybe whatsapp is also doing the same thing. Below is the chat code:
See images below to see it working.
XML Design:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rel_layout_left"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/txtDate"
android:visibility="visible"
android:orientation="vertical"
>
<TextView
android:id="#+id/lblMsgFrom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="kfhdjbh"
android:textColor="#color/lblFromName"
android:textSize="12dp"
android:textStyle="italic"
android:visibility="gone" />
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="#+id/lblMsgFrom"
android:layout_marginRight="-5dp"
android:src="#drawable/bubble_corner" />
<FrameLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#drawable/bg_msg_from"
android:layout_toRightOf="#+id/imageView">
<TextView
android:id="#+id/txtTimeFrom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="#dimen/d5"
android:text="Time"
android:textColor="#android:color/darker_gray"
android:layout_gravity="bottom|right"
android:padding="4dp"
android:textSize="10dp"
android:textStyle="italic"
android:layout_below="#+id/txtMsgFrom"
android:layout_alignRight="#+id/txtMsgFrom"
android:layout_alignEnd="#+id/txtMsgFrom" />
<TextView
android:id="#+id/txtMsgFrom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/imageView"
android:layout_toEndOf="#+id/lblMsgFrom"
android:layout_toRightOf="#+id/imageView"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="kdfjhgjfhf"
android:textColor="#color/black"
android:textSize="16dp"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_alignParentTop="true"
android:layout_marginTop="0dp"
android:layout_gravity="left|center_vertical" />
</FrameLayout>
</RelativeLayout>
Code: bg_msg_from.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<!-- view background color -->
<!--<solid android:color="#color/bg_msg_from" >-->
<solid android:color="#android:color/white" >
</solid>
<corners android:radius="#dimen/d5" >
</corners>
</shape>
** File: bubble_corner.png**
txtMsgFrom.setText(Html.fromHtml(convertToHtml(txtMsgFrom.getText().toString()) + "         ")); // 10 spaces
Its easier with Unicode from here.
So with this you can archive the Unicode format
new TextView("Hello\u00A0world");
better than HTML string.
source: https://stackoverflow.com/a/6565049
Based on #Sinan Ergin answer but slightly improved:
less layouts
simplified gravity + layout_gravity usage
left + right layout files
FrameLayout instead of RelativeLayout
converted to Kotlin
no attrs.xml & style references
/**
* Layout that allows a [TextView] to flow around a [View].
*
* First child must be of type [TextView].
* Second child must be of type [View].
*/
class TextViewContainerFlowLayout #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
private val textView by lazy(NONE) { getChildAt(0) as TextView }
private val containerView by lazy(NONE) { getChildAt(1) }
private val viewPartMainLayoutParams by lazy(NONE) { textView.layoutParams as LayoutParams }
private val viewPartSlaveLayoutParams by lazy(NONE) { containerView.layoutParams as LayoutParams }
private var containerWidth = 0
private var containerHeight = 0
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
var widthSize = MeasureSpec.getSize(widthMeasureSpec)
if (widthSize <= 0) {
return
}
val availableWidth = widthSize - paddingLeft - paddingRight
val textViewWidth = textView.measuredWidth + viewPartMainLayoutParams.leftMargin + viewPartMainLayoutParams.rightMargin
val textViewHeight = textView.measuredHeight + viewPartMainLayoutParams.topMargin + viewPartMainLayoutParams.bottomMargin
containerWidth = containerView.measuredWidth + viewPartSlaveLayoutParams.leftMargin + viewPartSlaveLayoutParams.rightMargin
containerHeight = containerView.measuredHeight + viewPartSlaveLayoutParams.topMargin + viewPartSlaveLayoutParams.bottomMargin
val viewPartMainLineCount = textView.lineCount
val viewPartMainLastLineWidth = if (viewPartMainLineCount > 0) textView.layout.getLineWidth(viewPartMainLineCount - 1) else 0.0f
widthSize = paddingLeft + paddingRight
var heightSize = paddingTop + paddingBottom
if (viewPartMainLineCount > 1 && viewPartMainLastLineWidth + containerWidth < textView.measuredWidth) {
widthSize += textViewWidth
heightSize += textViewHeight
} else if (viewPartMainLineCount > 1 && viewPartMainLastLineWidth + containerWidth >= availableWidth) {
widthSize += textViewWidth
heightSize += textViewHeight + containerHeight
} else if (viewPartMainLineCount == 1 && textViewWidth + containerWidth >= availableWidth) {
widthSize += textView.measuredWidth
heightSize += textViewHeight + containerHeight
} else {
widthSize += textViewWidth + containerWidth
heightSize += textViewHeight
}
setMeasuredDimension(widthSize, heightSize)
super.onMeasure(
MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY)
)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
textView.layout(
paddingLeft,
paddingTop,
textView.width + paddingLeft,
textView.height + paddingTop
)
containerView.layout(
right - left - containerWidth - paddingRight,
bottom - top - paddingBottom - containerHeight,
right - left - paddingRight,
bottom - top - paddingBottom
)
}
}
view_chat_entry.xml
<my.ui.view.TextViewContainerFlowLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:gravity="left|center_vertical"
android:padding="12dp"
>
<my.ui.android.TextView
android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:gravity="left|top"
android:textIsSelectable="true"
tools:text="hjjfg"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="bottom"
>
<TextView
android:id="#+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:maxLines="1"
/>
<my.ui.view.ChatEntryStatusView
android:id="#+id/status"
android:layout_width="wrap_content"
android:layout_marginStart="4dp"
android:layout_height="wrap_content"
/>
</LinearLayout>
</my.ui.view.TextViewContainerFlowLayout>
view_chat_entry_status.xml
<?xml version="1.0" encoding="utf-8"?>
<merge 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"
tools:layout_width="wrap_content"
tools:layout_height="wrap_content"
tools:parentTag="android.widget.FrameLayout"
>
<ImageView
android:contentDescription="#null"
android:id="#+id/statusImageView"
android:layout_width="15dp"
android:layout_height="15dp"
app:srcCompat="#drawable/ic_check_one"/>
</merge>
adapter_item_chat_left.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="64dp"
android:layout_marginTop="4dp"
android:gravity="left"
>
<include
layout="#layout/view_chat_entry"
android:id="#+id/chatEntry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
adapter_item_chat_right.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginStart="64dp"
android:layout_marginTop="4dp"
android:gravity="right"
>
<include
layout="#layout/view_chat_entry"
android:id="#+id/chatEntry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
End result (styling is done on the container with a drawable):
I propose another solution
public static final String TAG = "MainActivity";
private TextView mText;
private RelativeLayout relativeLayout;
private Boolean mFirstTime = true;
private static final int WIDH_HOUR = 382;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final int width = getScreensWidh();
mText = (TextView) findViewById(R.id.activity_main_text);
relativeLayout = (RelativeLayout) findViewById(R.id.activity_main_relative);
mText.setText("aaaaa dfsafsa afdsfa fdsafas adfas fdasf adfsa dsa aaaa dfsafsa afdsfa fdsafas adfas fdasf adfsa");
ViewTreeObserver vto = mText.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (mFirstTime) {
Layout layout = mText.getLayout();
int lines = layout.getLineCount();
int offset = layout.layout.getLineWidth(lines - 1);
int freeSpace = width - offset;
TextView hour = new TextView(MainActivity.this);
hour.setText("12:20");
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
if (freeSpace > WIDH_HOUR) {
params.addRule(RelativeLayout.ALIGN_BOTTOM, R.id.activity_main_text);
} else {
params.addRule(RelativeLayout.BELOW, R.id.activity_main_text);
}
hour.setLayoutParams(params);
relativeLayout.addView(hour);
Log.d(TAG, String.valueOf(freeSpace));
mFirstTime = false;
}
}
});
}
public int getScreensWidh() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size.x;
}
Two Public Methods
public abstract int getLineCount ()
Return the number of lines of text in this layout.
public int getLineWidth(int line)
Gets the unsigned horizontal extent of the specified line, including leading margin indent and trailing whitespace.
You can use the layout and code below to achieve the desired effect.
Source code gist
What I have used is get the width of the text + the time layout and check if this exceeds the container layout width, and adjust the height of the container accordingly. We have to extend from FrameLayout since this is the one which allows overlapping of two child views.
This is tested to be working on English locale. Suggestions and improvements are always welcome :)
Hope I've helped someone looking for the same solution.
I guess the easiest way to achieve this kind oflayout would be to add enough blank space in your message to be sure there is enough space on the right to not cover the time (I don't see any other easy way to have a margin/padding/positioning for the last line of your text only)
Then you just place the time in the relative as an align bottom right
layout_chat_left.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layoutChat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp">
<RelativeLayout
android:id="#+id/message_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_toRightOf="#id/test_arrow"
android:background="#drawable/bg_msg_left"
android:paddingLeft="15dp"
android:paddingTop="5dp"
android:paddingRight="15dp"
android:paddingBottom="7dp"
tools:ignore="UselessParent">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:maxWidth="200dp"
android:text="demo Text"
android:textColor="#222"
android:textSize="17sp" />
<TextClock
android:id="#+id/msg_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/text"
android:layout_toEndOf="#+id/text"
android:text="1:30 P.M."
android:textColor="#888" />
<ImageView
android:id="#+id/is_Read_iv"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginBottom="2dp"
android:layout_marginLeft="2dp"
android:layout_alignBottom="#+id/text"
android:layout_toEndOf="#+id/msg_time"
android:src="#drawable/icon_tick"
android:tint="#color/BlueTint"/>
</RelativeLayout>
<ImageView
android:id="#+id/test_arrow"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentLeft="true"
android:layout_marginTop="1dp"
android:layout_marginRight="-6dp"
android:background="#null"
android:scaleX="-1.5"
android:src="#drawable/v_bubble_corner_left" />
</RelativeLayout>
layout_chat_right.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layoutChat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp">
<RelativeLayout
android:id="#+id/message_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_toLeftOf="#id/test_arrow"
android:background="#drawable/bg_msg_right"
android:paddingLeft="15dp"
android:paddingTop="5dp"
android:paddingRight="15dp"
android:paddingBottom="7dp"
tools:ignore="UselessParent">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:maxWidth="200dp"
android:text="demo Text"
android:textColor="#222"
android:textSize="17sp" />
<TextClock
android:id="#+id/msg_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/text"
android:layout_toEndOf="#+id/text"
android:text="1:30 P.M."
android:textColor="#888" />
<ImageView
android:id="#+id/is_Read_iv"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginBottom="2dp"
android:layout_marginLeft="2dp"
android:layout_alignBottom="#+id/text"
android:layout_toEndOf="#+id/msg_time"
android:src="#drawable/icon_tick"
android:tint="#color/BlueTint" />
</RelativeLayout>
<ImageView
android:id="#+id/test_arrow"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:layout_marginLeft="-6dp"
android:layout_marginTop="1dp"
android:background="#null"
android:scaleX="1.5"
android:src="#drawable/v_bubble_corner_right" />
</RelativeLayout>
bg_msg_left.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<!-- view background color -->
<!--<solid android:color="#color/bg_msg_right" >-->
<solid android:color="#color/white" >
</solid>
<corners
android:topLeftRadius="0dp"
android:topRightRadius="5dp"
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp">
</corners>
</shape>
bg_msg_right.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<!-- view background color -->
<!--<solid android:color="#color/bg_msg_right" >-->
<solid android:color="#color/whatsapp_green" >
</solid>
<corners
android:topLeftRadius="5dp"
android:topRightRadius="0dp"
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp">
</corners>
</shape>
v_bubble_corner_left.xml
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#color/white"
android:pathData="M8,5v14l11,-14z" />
</vector>
v_bubble_corner_right.xml
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#color/whatsapp_green"
android:pathData="M8,5v14l11,-14z"/>
</vector>
And the CommentAdapter.java is
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.daimajia.androidanimations.library.Techniques;
import com.daimajia.androidanimations.library.YoYo;
import com.google.android.material.card.MaterialCardView;
import java.util.ArrayList;
import java.util.List;
public class CommentAdapter extends RecyclerView.Adapter<CommentAdapter.ViewHolder> {
private List<String> mComment;
private List<String> mTimeData;
private List<Integer> mIcon;
private List<Integer> mDirection;
private List<Integer> mRecordID;
private Context mContext;
private LayoutInflater mInflater;
private static final String TAG = "CommentAdapter";
private ItemLongClickListener mLongClickListener;
// data is passed into the constructor
CommentAdapter(Context context, List<String> dataComment, List<String> dataTimeData, List<Integer> dataDirection, List<Integer> dataRecordID) {
mContext = context;
this.mInflater = LayoutInflater.from( context );
this.mComment = dataComment;
this.mTimeData = dataTimeData;
this.mDirection = dataDirection;
this.mRecordID = dataRecordID;
}
// inflates the row layout from xml when needed
#NonNull
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == 1) {
view = mInflater.inflate( R.layout.layout_chat_left, parent, false );
} else {
view = mInflater.inflate( R.layout.layout_chat_right, parent, false );
}
return new ViewHolder( view );
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String mTitle = mComment.get( position );
holder.tvComment.setText( mTitle );
String mSubTitle = mTimeData.get( position );
holder.tvTime.setText( mSubTitle );
int maxWidth = mContext.getResources().getDisplayMetrics().widthPixels;
holder.layoutChat.getLayoutParams().width = maxWidth;
}
// total number of rows
#Override
public int getItemCount() {
return mComment.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener {
TextView tvComment;
TextView tvTime;
TextView tvSerial;
RelativeLayout layoutChat;
MaterialCardView cardView;
ViewHolder(View itemView) {
super( itemView );
tvComment = itemView.findViewById( R.id.text );
tvTime = itemView.findViewById( R.id.msg_time );
layoutChat = itemView.findViewById( R.id.layoutChat );
itemView.setOnLongClickListener( this );
}
#Override
public boolean onLongClick(View v) {
Log.d( TAG, "onLongClick: " + getAdapterPosition() );
if (mLongClickListener!=null)
mLongClickListener.onItemLongClick( v, mRecordID.get( getAdapterPosition() ) );
return true;
}
}
void setOnLongClickListener(ItemLongClickListener itemLongClickListener) {
this.mLongClickListener = itemLongClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemLongClickListener {
void onItemLongClick(View view, int position);
}
#Override
public int getItemViewType(int position) {
if (mDirection.get( position ) == 1)
return 1;
return 2;
}
}
Here are the screenshots, one from a live demo
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rel_layout_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/bubble1"
android:orientation="vertical">
<TextView
android:id="#+id/lblMsgFrom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Person Name or Id"
android:visibility="gone" />
<TextView
android:id="#+id/lblMessage_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:text="Sample \n Sample2 Sample2 Sample2 Sample2 Sample2 Sample2 Sample2 Sample2 Sample2 \n Sample2"
android:textSize="16dp" />
<TextView
android:id="#+id/lblMessage_Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="#+id/lblMessage_text"
android:layout_alignRight="#+id/lblMessage_text"
android:layout_below="#+id/lblMessage_text"
android:text="04:50 Am"
android:textColor="#android:color/darker_gray"
android:textSize="10dp"
android:textStyle="italic" />
</RelativeLayout>
I suggest other solution. If you know max bubble width and time width, then you can precalculate how to place your views.
Layout:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
tools:text="This is text"/>
<TextView
android:id="#+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="10sp"
tools:text="10:10"/>
</RelativeLayout>
Code:
fun setTextAndTime(textView: TextView, timeView: TextView, text: String, time: String) {
// screen width - offset from bubble
val maxWidth: Int = Resources.getSystem().displayMetrics.widthPixels - context.resources.getDimensionPixelSize(R.dimen.bubble_offset)
val timeWidth: Int = getTextWidth(time, 10f)
textView.text = text
timeView.text = time
textView.measure(makeMeasureSpec(maxWidth, EXACTLY), makeMeasureSpec(0, UNSPECIFIED))
val offset = textView.layout.getLineWidth(textView.layout.lineCount - 1)
val freeSpace = maxWidth - offset
val moveTimestampBelow = freeSpace < timeWidth
val multilineContent = textView.layout.lineCount > 1
val params = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT)
when {
moveTimestampBelow -> params.apply {
addRule(RelativeLayout.BELOW, textView.id)
addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
}
multilineContent -> params.apply {
params.addRule(RelativeLayout.ALIGN_BOTTOM, textView.id)
addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
}
else -> params.apply {
params.addRule(RelativeLayout.ALIGN_BOTTOM, textView.id)
addRule(RelativeLayout.END_OF, textView.id)
}
}
timeView.layoutParams = params
}
private fun getTextWidth(text: String, textSizeSp: Float): Int {
val textPaint = Paint()
val pxSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSizeSp, context.resources.displayMetrics)
textPaint.textSize = pxSize
textPaint.style = Paint.Style.FILL
val result = Rect()
textPaint.getTextBounds(text, 0, text.length, result)
return result.width()
}
The previous answers didn't satisfy my needs as they were too complex and the scrolling on RecyclerView was way too slow! I could feel the stutter while scrolling. So, I modified #Rahul Shuklas answer to make it more efficient. I am sharing my result below. The code is self explanatory, I have added comments for more understandability.
class ChatBubbleLayout : FrameLayout {
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
#TargetApi(21)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
doMeasure()
}
private fun doMeasure() {
val messageTextView = findViewById<TextView>(R.id.tv_message)
val dateTextView = findViewById<TextView>(R.id.tv_message_time)
// Message line count
val lineCount = messageTextView.lineCount
// Message padding
val messageTextViewPadding = messageTextView.paddingLeft + messageTextView.paddingRight
// First / Second last line of message
val lastLineStart = messageTextView.layout.getLineStart(lineCount - 1)
val lastLineEnd = messageTextView.layout.getLineEnd(lineCount - 1)
// Width of First / Second last line of message
var desiredWidth = Layout.getDesiredWidth(messageTextView.text.subSequence(lastLineStart,
lastLineEnd), messageTextView.paint).toInt()
var desiredHeight = measuredHeight
if (desiredWidth < minimumWidth && messageTextView.measuredWidth < minimumWidth) {
// Probably a small or single line message
desiredWidth = minimumWidth + messageTextViewPadding
} else {
// Probably a bit long or multiple line message
desiredWidth = messageTextView.measuredWidth + messageTextViewPadding
}
if(desiredHeight < minimumHeight) {
desiredHeight = minimumHeight
}
setMeasuredDimension(desiredWidth, desiredHeight)
}
}
My Layout XML file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right">
<com.app.chat.ui.ChatBubbleLayout
android:id="#+id/chat_bubble_item_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="#dimen/height_16dp"
android:background="#drawable/medium_green_rounded_corner"
android:minWidth="96dp"
android:minHeight="44dp">
<TextView
android:id="#+id/tv_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|left"
android:autoLink="all"
android:linksClickable="true"
android:maxWidth="280dp"
android:paddingLeft="#dimen/margin_8dp"
android:paddingTop="#dimen/margin_8dp"
android:paddingRight="#dimen/margin_8dp"
android:paddingBottom="#dimen/margin_8dp"
android:text="#{chatMessageVM.iMessage.message}"
android:textColor="#color/white"
android:textColorLink="#color/white"
android:textIsSelectable="true"
android:textSize="#dimen/text_14sp"
tools:text="Nope" />
<TextView
android:id="#+id/tv_message_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|right|bottom"
android:layout_marginRight="#dimen/margin_4dp"
android:layout_marginBottom="#dimen/margin_2dp"
android:gravity="center_vertical"
android:text="#{chatMessageVM.iMessage.readableTimestamp}"
android:textColor="#color/gray_5"
android:textSize="#dimen/text_12sp"
tools:text="11:21 AM" />
</com.app.chat.ui.ChatBubbleLayout>
</LinearLayout>
I hope it helps future readers.
Here is my Layout file chat_row_right_1.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_toLeftOf="#+id/test_arrow"
android:id="#+id/message_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingBottom="7dp"
android:paddingTop="5dp"
android:paddingRight="15dp"
android:layout_marginTop="5dp"
android:maxWidth="200dp"
android:background="#drawable/layout_bg2_1"
tools:ignore="UselessParent">
<TextView
android:layout_marginEnd="10dp"
android:id="#+id/text"
android:text="demo Text"
android:textColor="#222"
android:textSize="17sp"
android:layout_width="wrap_content"
android:maxWidth="200dp"
android:layout_height="wrap_content" />
<TextClock
android:id="#+id/msg_time"
android:layout_toEndOf="#+id/text"
android:layout_alignBottom="#+id/text"
android:text="1:30 P.M."
android:textColor="#888"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="#+id/is_Read_iv"
android:layout_toEndOf="#+id/msg_time"
android:layout_alignBottom="#+id/text"
android:layout_width="wrap_content"
android:src="#drawable/ic_done_black_24dp"
android:layout_height="wrap_content" />
</RelativeLayout>
<ImageView
android:id="#+id/test_arrow"
android:layout_alignParentRight="true"
android:layout_width="20dp"
android:background="#null"
android:layout_marginTop="-2dp"
android:layout_marginLeft="-8dp"
android:layout_height="wrap_content"
android:src="#drawable/ic_play_arrow_black_24dp"/>
</RelativeLayout>
And here is ic_right_bubble.xml file in drawable folder
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#cfc"
android:pathData="M8,5v14l11,-14z"/>
</vector>
You will get exact same as WhatsApp See screenshot

error after add relativelayout inside linearlayout?

I want to display the video thumbnails in listview, I use images instead of thumbnails and add ImageView (image play button) on the front but failed my xml code like this
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/txttgl"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:paddingLeft="10dip"
android:gravity="center_horizontal"/>
<TextView
android:id="#+id/tv_batas_unread"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:paddingLeft="12dip"
android:background="#drawable/counter_shape_birudonker"
android:visibility="gone"
android:gravity="center_horizontal"/>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/ll_chat_item"
android:orientation="horizontal" >
<com.ltvie.chatkrawala.ImageViewRounded
android:id="#+id/img_photo_pp_chatbox"
android:layout_width="50dp"
android:layout_height="50dp"
android:paddingBottom="0dp"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:adjustViewBounds="true"
android:paddingTop="0dp"
android:layout_marginTop="5dp"
android:layout_marginLeft="3dp"
android:src="#drawable/gada_photo"
android:scaleType="fitXY" />
<LinearLayout
android:id="#+id/wrapper"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="left"
android:orientation="vertical"
android:layout_marginBottom="12dp"
android:layout_weight="1"
android:cacheColorHint="#android:color/transparent"
>
<TextView
android:id="#+id/txtKodeGbr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
<TextView
android:id="#+id/txtPesan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
<TextView
android:id="#+id/comment"
android:layout_marginTop="9dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/buble_kiri"
android:text="Bismillahirohmanirrohim"
android:textColor="#000"
android:textSize="15sp" />
<LinearLayout
android:id="#+id/rowFile"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="wrap_content"
>
<ImageView
android:id="#+id/img_dilvChat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:contentDescription="#string/descGambar"
android:background="#drawable/buble_kanan"
android:src="#drawable/gada_photo"
/>
<ImageView
android:id="#+id/img_btn_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/descGambar"
android:layout_centerInParent="true"
android:src="#drawable/play_icon"
/>
<ProgressBar
android:id="#+id/chatBox_progress_img"
style="?android:attr/progressBarStyleSmallInverse"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
<LinearLayout
android:id="#+id/rowFileDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_gravity="bottom"
android:orientation="vertical">
<TextView
android:id="#+id/txtFileName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dip"
android:gravity="left"
android:text="Nama File : test.zip"
android:textSize="12sp" />
<TextView
android:id="#+id/txtFileSize"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dip"
android:gravity="left"
android:text="Ukuran : 2324342 bytes"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/img_statusBaca"
android:layout_marginTop="2dip"
android:layout_width="15dip"
android:layout_height="15dip"
android:layout_marginRight="1dip"
android:background="#drawable/indicator_sending"
android:contentDescription="#string/descGambar"
/>
<TextView
android:id="#+id/txtjamchatMasuk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dip"
android:gravity="left"
android:text="setatus baca"
android:textSize="12sp" />
<TextView
android:id="#+id/txtKiriKanan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:text="right"
android:visibility="gone"
/>
</LinearLayout>
</LinearLayout>
<ImageView
android:id="#+id/imgselected"
android:layout_width="20dp"
android:layout_height="20dp"
android:contentDescription="#string/kosongan"
android:src="#drawable/ico_member" />
</LinearLayout>
</LinearLayout>
my java code
public class ChatboxArrayAdapter extends ArrayAdapter<OneComment> implements SectionIndexer{
private TextView countryName;
private LinearLayout wrapper,rowFileDesc,ll_chat_item;
private TextView TanggalMasuk,txtKodeGbr,txtPesan,txtJam,txtKiriKanan,txtUkuranFile;
private ImageView img_upload,img_statusbaca,imgPp_round;
ImageView imgPhoto,imgCheck,imgBtnPlay;
String namafileGambar,strPath,varStsBaca,tampilTgl;
public CacheImageLoader imageLoader;
Context ctx;
Options opts = new BitmapFactory.Options();
String TAG="chatboxArrayAdapter";
File dir = new File(Environment.getExternalStorageDirectory()+"");
File dirImage=new File(dir+"/a");
File dirVideo=new File(dir+"/a");
List<OneComment> countries;
#Override
public void add(OneComment object) {
countries.add(object);
super.add(object);
}
public void hapus_semua(){
countries.clear();
}
public void hapus_item(int nomerx){
countries.remove(nomerx);
notifyDataSetChanged();
}
public void refresh_lv(){
notifyDataSetChanged();
Log.d("notify", "datachange");
}
public ChatboxArrayAdapter(Context context, int textViewResourceId, List<OneComment> datanya) {
super(context, textViewResourceId);
this.countries=datanya;
this.ctx=context;
imageLoader=new CacheImageLoader(context.getApplicationContext());
}
public int getCount() {
return this.countries.size();
}
#Override
public OneComment getItem(int index) {
return this.countries.get(index);
}
public View getView(final int position, View convertView, ViewGroup parent) {
View row = convertView;
try{
if (row == null) {
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.chatbox_detail, parent, false);
}
OneComment isiOneComen = getItem(position);
wrapper = (LinearLayout) row.findViewById(R.id.wrapper);
rowFileDesc=(LinearLayout) row.findViewById(R.id.rowFileDesc);
ll_chat_item=(LinearLayout) row.findViewById(R.id.ll_chat_item);
imgPhoto = (ImageView) row.findViewById(R.id.img_dilvChat);
countryName = (TextView) row.findViewById(R.id.comment);
txtKiriKanan = (TextView) row.findViewById(R.id.txtKiriKanan); //isi dari coment untuk menentukan letak buble di kiri ato dikanan,hanya untuk buble file untuk menentukan filenya masih di server apa sudah di downloa
TanggalMasuk= (TextView) row.findViewById(R.id.txttgl);
img_upload=(ImageView) row.findViewById(R.id.img_dilvChat);
txtKodeGbr = (TextView) row.findViewById(R.id.txtKodeGbr);
txtPesan=(TextView) row.findViewById(R.id.txtPesan);
txtJam=(TextView) row.findViewById(R.id.txtjamchatMasuk);
txtUkuranFile=(TextView) row.findViewById(R.id.txtFileSize);
imgCheck=(ImageView) row.findViewById(R.id.imgselected);
img_statusbaca=(ImageView) row.findViewById(R.id.img_statusBaca);
imgPp_round=(ImageView) row.findViewById(R.id.img_photo_pp_chatbox);
imgBtnPlay=(ImageView) row.findViewById(R.id.img_btn_play);
txtPesan.setVisibility(View.GONE);
txtKodeGbr.setVisibility(View.GONE);
img_upload.setVisibility(View.GONE);
rowFileDesc.setVisibility(View.GONE);
if(isiOneComen.comment.trim().equalsIgnoreCase("video")){
//error goes here
countryName.setVisibility(View.GONE);
Log.d("fileDesc", isiOneComen.Filedesc);
//strPath = namafileGambar;
strPath = moduleGlobal.dirImageSent+"/"+isiOneComen.Filedesc;
imgPhoto.setImageBitmap(changeSize(strPath));
scaleImage(imgPhoto, ((int) isiOneComen.lebarScreen)-((int) isiOneComen.lebarScreen/4));
imgBtnPlay.setVisibility(View.VISIBLE);
}else{ //run work well
countryName.setVisibility(View.VISIBLE);
try{
countryName.setText(getSmiledText(getContext(),isiOneComen.comment.toString()));
}catch (Exception e) {
// TODO: handle exception
Log.e("addsmiley", e.toString());
}
countryName.setBackgroundResource(isiOneComen.left ? R.drawable.buble_kiri : R.drawable.buble_kanan);
}
}catch (Exception ez) {
ll_chat_item.setVisibility(View.GONE);
Log.e(TAG, ez.toString());
}
return row;
}
private Bitmap changeSize(String path){
opts.inSampleSize = 1;
Bitmap bm = BitmapFactory.decodeFile(path);
if (bm.getHeight() > 150 || bm.getWidth() > 150) {
final int halfHeight = bm.getHeight() / 2;
final int halfWidth = bm.getWidth() / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / opts.inSampleSize) > 150
&& (halfWidth / opts.inSampleSize) > 150) {
opts.inSampleSize *= 2;
}
}
bm = BitmapFactory.decodeFile(path,opts); // this bitmap will be 1/8 the size of the original
return bm;
}
private void scaleImage(ImageView view, int boundBoxInDp)
{
// Get the ImageView and its bitmap
Drawable drawing = view.getDrawable();
Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
// Get current dimensions
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) boundBoxInDp) / width;
float yScale = ((float) boundBoxInDp) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// Create a new bitmap and convert it to a format understood by the ImageView
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
#SuppressWarnings("deprecation")
BitmapDrawable result = new BitmapDrawable(scaledBitmap);
width = scaledBitmap.getWidth();
height = scaledBitmap.getHeight();
// Apply the scaled bitmap
view.setImageDrawable(result);
// Now change ImageView's dimensions to match the scaled image
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
public Bitmap decodeToBitmap(byte[] decodedByte) {
return BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length);
}
/**tambah smiley
*
*/
private static final HashMap<String, Integer> emoticons = new HashMap<String, Integer>();
static {
emoticons.put(":)", R.drawable.s1);
emoticons.put(":D", R.drawable.s2);
emoticons.put(":(", R.drawable.s3);
emoticons.put("8o|", R.drawable.s16);
emoticons.put(":/", R.drawable.s17);
}
// Get image for each text smiles
public static Spannable getSmiledText(Context context, String text) {
SpannableStringBuilder builder = new SpannableStringBuilder(text);
int index;
for (index = 0; index < builder.length(); index++) {
for (Entry<String, Integer> entry : emoticons.entrySet()) {
int length = entry.getKey().length();
if (index + length > builder.length())
continue;
if (builder.subSequence(index, index + length).toString().equals(entry.getKey())) {
builder.setSpan(new ImageSpan(context, entry.getValue()), index, index + length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
index += length - 1;
break;
}
}
}
return builder;
}
#Override
public int getPositionForSection(int arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public int getSectionForPosition(int arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public Object[] getSections() {
// TODO Auto-generated method stub
return null;
}
}
everything work well before i add relative layout,I want to add image view center with other imageview but I get error log
java.lang.ClassCastException: android.widget.RelativeLayout$LayoutParams
Problem with
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
This line Change this line to
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
Because you forgot to Add
</LinearLayout>
</LinearLayout>
at the end of your xml.
Use this
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/tv1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:gravity="center_horizontal"
android:paddingLeft="10dip" />
<LinearLayout
android:id="#+id/ll_chat_item"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<LinearLayout
android:id="#+id/wrapper"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:layout_weight="1"
android:cacheColorHint="#android:color/transparent"
android:gravity="left"
android:orientation="vertical" >
<TextView
android:id="#+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone" />
<LinearLayout
android:id="#+id/rowFile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/img_dilvChat"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_margin="3dp"
android:background="#drawable/buble_kanan"
android:contentDescription="#string/descGambar" />
<ImageView
android:id="#+id/img_btn_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:contentDescription="#string/descGambar"
android:src="#drawable/play_icon" />
</RelativeLayout>
<TextView
android:id="#+id/tv4"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:gravity="center_horizontal"
android:paddingLeft="10dip" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

Android screen resolution issue

I have two tablets. I have run a test resolution app to get screen parameters. Thouse are the results.
1) Coby MID7042 7": low density, scale: 0.75, 120dpi, 480 x 764,
layout for large screen, drawable LDPI.
2) BQ Elcano 7": high density, scale: 1.5, 240dpi, 800 x 1208, layout
for large screen, drawable HDPI.
I have developed an android application that fits good on Coby screen, but in BQ the screen is cut in the right and in the bottom. That is, the screen is bigger than you can see on the screen. I think BQ screen is better and bigger than Coby, but I don't know why it doesn't fit the screen.
In my developed android app, the xml file for the screen is into res/layout folder. I always use sp and dp.
I have read about "supporting multiple screen" and so on, but in this case, I think BQ should show the screen at right fit using the same layout. But it doesn't.
Some one could help me about this issue? I don't know how could I solve this, because two tablets are large for layouts.
Thanks.
Edited. This is a layout that is cut in the right (the latest EditText is cut):
<LinearLayout
style="#style/GroupBox3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_weight="1"
android:baselineAligned="true" >
<LinearLayout
android:layout_width="130dp"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/TextView08"
style="#style/etstyle1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="#string/Box" />
<EditText
android:id="#+id/eBox"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_weight="1"
android:background="#drawable/roundedittext"
android:ems="10"
android:enabled="true"
android:gravity="right"
android:inputType="number|numberSigned|numberDecimal"
android:selectAllOnFocus="true" >
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="130dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:orientation="vertical" >
<TextView
android:id="#+id/TextView06"
style="#style/etstyle1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="#string/Uds" />
<EditText
android:id="#+id/euds"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:background="#drawable/roundedittext"
android:ems="10"
android:enabled="true"
android:gravity="right"
android:inputType="number|numberSigned|numberDecimal"
android:selectAllOnFocus="true" />
</LinearLayout>
<LinearLayout
android:layout_width="130dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:orientation="vertical" >
<TextView
android:id="#+id/TextView09"
style="#style/etstyle1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|left"
android:paddingLeft="10dp"
android:text="#string/Tar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingBottom="5dp" >
<EditText
android:id="#+id/etar"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="#drawable/roundedittext"
android:ems="10"
android:enabled="true"
android:gravity="center_vertical|right"
android:inputType="number"
android:selectAllOnFocus="true" />
<Button
android:id="#+id/btnTarifa"
style="#style/btnSer"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical|center_horizontal|center"
android:layout_marginTop="2dp"
android:text="#string/Inter" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="135dp"
android:layout_height="match_parent"
android:layout_marginLeft="5dp"
android:orientation="vertical" >
<TextView
android:id="#+id/etit"
style="#style/etstyle1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="#string/price" />
<EditText
android:id="#+id/eprice"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:background="#drawable/roundedittext"
android:ems="10"
android:enabled="true"
android:gravity="center_vertical|right"
android:inputType="numberDecimal"
android:selectAllOnFocus="true" />
</LinearLayout>
</LinearLayout>
DroidUsers answer is little bit confusing but method is effective...
look for more effective example:
http://www.vanteon.com/downloads/Scaling_Android_Apps_White_Paper.pdf
I have Used one approach where I design the Layout I wanted in a standard device, and store all dynamically apply all the layout dependent values(eg: padding, margin etc) using a seperate class. And by calculating a ratio with current device config to the standard i have stored,
I will give you my sample code. just go through it and find your way accordingly
public class ListViewDimensions
{
private Context _context;
private Configuration config;
private Display display;
private int _width;
private int _height;
private int _portOrLand;
private int _ORIENTATION_LAND=2;
private int _ORIENTATION_PORT=1;
private DisplayMetrics metrics;
private Dimension dimension;
//***************************** PORTRAIT ********************************\\
public int PlistLayoutPaddingLeft=16;
public int PlistLayoutPaddingRight=16;
public int PlistLayoutPaddingTop=16;
public int PlistLayoutPaddingBottom=15;
public int PsuraNoTextsize=10;
public int PsuraNameTextsize=20;
public int PayaNoTextsize=10;
public int PsuraNameWidth=180;
public int PpageNoTextsize=10;
public int PpageNoPadding=2;
public int PmalayalamFontsize;
public int ParabiFontsize;
public int PsuraHeadHeight=40;
//----------------------------------------------------------------------------------------
//***************************** LANDSCAPE IN TABS ********************************\\
public int LTlistLayoutPaddingLeft=35;
public int LTlistLayoutPaddingTop=30;
public int LTlistLayoutPaddingRight=35;
public int LTlistLayoutPaddingRightRightPage=35;
public int LTlistLayoutPaddingBottom=5;
public int LTpageNoTextsize=13;
public int LTpageNoPadding=0;
public int LTsuraNoTextsize=15;
public int LTsuraNameTextsize=25;
public int LTayaNoTextsize=15;
public int LTsuraNameWidth=375;
public int LTmalayalamFontsize;
public int LTarabiFontsize;
public int LTsuraHeadHeight=60;
//----------------------------------------------------------------------------------------
//***************************** LANDSCAPE IN NON-TABS ********************************\\
public int LlistLayoutPaddingLeft=21;
public int LlistLayoutPaddingRight=20;
public int LlistLayoutPaddingTop=16;
public int LlistLayoutPaddingBottom=17;
public int LsuraNoTextsize=10;
public int LsuraNameTextsize=20;
public int LayaNoTextsize=10;
public int LsuraNameWidth=330;
public int LpageNoTextsize=13;
public int LpageNoPadding=3;
public int LmalayalamFontsize;
public int LarabiFontsize;
public int LsuraHeadHeight=40;
//----------------------------------------------------------------------------------------
public float xScale;
private float yScale;
private double diagonalInches;
public class Dimension
{
public int listLayoutPaddingLeft;
public int listLayoutPaddingRight;
public int listLayoutPaddingTop;
public int listLayoutPaddingBottom;
public int pageNoTextsize;
public int pageNoPadding;
public int suraNoTextsize;
public int suraNameTextsize;
public int ayaNoTextsize;
public int suraNameWidth;
public int malayalamFontsize;
public int arabiFontsize;
public int suraHeadHeight;
public String bismi;
}
public ListViewDimensions.Dimension getDimensions(Context c)
{
PmalayalamFontsize=MyApp.appSettings.listMalayalamFontSize;
ParabiFontsize=MyApp.appSettings.listMalayalamFontSize;
LTmalayalamFontsize=MyApp.appSettings.listMalayalamFontSize*2;
LTarabiFontsize=MyApp.appSettings.listMalayalamFontSize*2;
LmalayalamFontsize=MyApp.appSettings.listMalayalamFontSize;
LarabiFontsize=MyApp.appSettings.listMalayalamFontSize;
dimension=new Dimension();
_context=c;
config =c.getResources().getConfiguration();
display=((Activity) c).getWindowManager().getDefaultDisplay();
_width = display.getWidth();
_height =display.getHeight();
if(config.orientation==config.ORIENTATION_LANDSCAPE)
_portOrLand=_ORIENTATION_LAND;
else
_portOrLand=_ORIENTATION_PORT;
metrics = new DisplayMetrics();
((Activity) c).getWindowManager().getDefaultDisplay().getMetrics(metrics);
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
int density=metrics.densityDpi;
float widthDpi = metrics.xdpi;
float heightDpi = metrics.ydpi;
if(density/widthDpi>1.2)
{
widthDpi=density;
heightDpi=density;
}
float widthInches = widthPixels / widthDpi;
float heightInches = heightPixels / heightDpi;
diagonalInches = Math.sqrt((widthInches * widthInches) + (heightInches * heightInches));
if(diagonalInches>=6.7 && _portOrLand==_ORIENTATION_LAND)
{
//TODO : for landscape in tabs
xScale = (_width/2)/(float)640 ;
yScale = _height/(float)752 ;
dimension.listLayoutPaddingLeft=LTlistLayoutPaddingLeft;
dimension.listLayoutPaddingRight=LTlistLayoutPaddingRight;
dimension.listLayoutPaddingTop=LTlistLayoutPaddingTop;
dimension.listLayoutPaddingBottom=LTlistLayoutPaddingBottom;
dimension.pageNoTextsize=LTpageNoTextsize;
dimension.pageNoPadding=LTpageNoPadding;
dimension.malayalamFontsize=LTmalayalamFontsize;
dimension.arabiFontsize=LTarabiFontsize;
dimension.suraNoTextsize=LTsuraNoTextsize;
dimension.suraNameTextsize=LTsuraNameTextsize;
dimension.ayaNoTextsize=LTayaNoTextsize;
dimension.suraNameWidth=LTsuraNameWidth;
dimension.suraHeadHeight=LTsuraHeadHeight;
dimension.bismi="&%$";
}
else if( _portOrLand==_ORIENTATION_PORT)
{
//TODO : for portrait in non-tab devices and tabs
xScale = _width/(float)320 ;
yScale = _height/(float)480 ;
dimension.listLayoutPaddingLeft=PlistLayoutPaddingLeft;
dimension.listLayoutPaddingRight=PlistLayoutPaddingRight;
dimension.listLayoutPaddingTop=PlistLayoutPaddingTop;
dimension.listLayoutPaddingBottom=PlistLayoutPaddingBottom;
dimension.pageNoTextsize=PpageNoTextsize;
dimension.pageNoPadding=PpageNoPadding; //TODO: check whether it is mandatory
dimension.malayalamFontsize=PmalayalamFontsize;
dimension.arabiFontsize=ParabiFontsize;
dimension.suraHeadHeight=PsuraHeadHeight;
dimension.suraNoTextsize=PsuraNoTextsize;
dimension.suraNameTextsize=PsuraNameTextsize;
dimension.ayaNoTextsize=PayaNoTextsize;
dimension.suraNameWidth=PsuraNameWidth;
if(diagonalInches<4.0)
dimension.bismi="ó";
else
dimension.bismi="&%$";
}
else if(diagonalInches<6.7 && _portOrLand==_ORIENTATION_LAND)
{
//TODO : for land in non-tab devices
xScale = _height/(float)320 ;
yScale = _width/(float)480 ;
dimension.listLayoutPaddingLeft=LlistLayoutPaddingLeft;
dimension.listLayoutPaddingRight=LlistLayoutPaddingRight;
dimension.listLayoutPaddingTop=LlistLayoutPaddingTop;
dimension.listLayoutPaddingBottom=LlistLayoutPaddingBottom;
dimension.suraHeadHeight=LsuraHeadHeight;
dimension.suraNoTextsize=LsuraNoTextsize;
dimension.suraNameTextsize=LsuraNameTextsize;
dimension.ayaNoTextsize=LayaNoTextsize;
dimension.suraNameWidth=LsuraNameWidth;
dimension.pageNoTextsize=LpageNoTextsize;
dimension.pageNoPadding=LpageNoPadding; //TODO: check whether it is mandatory
dimension.malayalamFontsize=LmalayalamFontsize;
dimension.arabiFontsize=LarabiFontsize;
dimension.suraHeadHeight=LsuraHeadHeight;
dimension.bismi="&%$";
}
dimension.listLayoutPaddingLeft=(int) (dimension.listLayoutPaddingLeft*xScale);
dimension.listLayoutPaddingRight=(int) (dimension.listLayoutPaddingRight*xScale);
dimension.listLayoutPaddingTop=(int) (dimension.listLayoutPaddingTop*yScale);
dimension.listLayoutPaddingBottom=(int) (dimension.listLayoutPaddingBottom*yScale);
dimension.pageNoTextsize=(int) (dimension.pageNoTextsize*xScale);
dimension.pageNoPadding=(int) (dimension.pageNoPadding*yScale);
dimension.malayalamFontsize=(int) (dimension.malayalamFontsize*xScale);
dimension.arabiFontsize=(int) (dimension.arabiFontsize*xScale);
dimension.suraHeadHeight=(int) (dimension.suraHeadHeight*yScale);
dimension.suraNoTextsize=(int) (dimension.suraNoTextsize*xScale);
dimension.suraNameTextsize=(int) (dimension.suraNameTextsize*xScale);
dimension.ayaNoTextsize=(int) (dimension.ayaNoTextsize*xScale);
dimension.suraNameWidth=(int) (dimension.suraNameWidth*xScale);
return this.dimension;
}
public ListViewDimensions.Dimension updateFontSize()
{
if(diagonalInches>=6.7 && _portOrLand==_ORIENTATION_LAND)
{
xScale = (_width/2)/(float)640 ;
yScale = _height/(float)752 ;
dimension.malayalamFontsize=LTmalayalamFontsize;
dimension.arabiFontsize=LTarabiFontsize;
}
else if( _portOrLand==_ORIENTATION_PORT)
{
xScale = _width/(float)320 ;
yScale = _height/(float)480 ;
dimension.malayalamFontsize=PmalayalamFontsize;
dimension.arabiFontsize=ParabiFontsize;
}
else if(diagonalInches<6.7 && _portOrLand==_ORIENTATION_LAND)
{
xScale = _height/(float)320 ;
yScale = _width/(float)480 ;
dimension.malayalamFontsize=LmalayalamFontsize;
dimension.arabiFontsize=LarabiFontsize;
}
dimension.malayalamFontsize=(int) (dimension.malayalamFontsize*xScale);
dimension.arabiFontsize=(int) (dimension.arabiFontsize*xScale);
return dimension;
}
}
You should try to work with android:layout_weight instead of specifying your LinearLayout's android:layout_width="130dp". This way, the widths of your textviews and edittexts and what not can be set to fill_parent and Android will scale anything to the size of your screen, whatever the device you're working on might be.
With an exception for the linear layout where you have a new linearlayout for the edittext and a button, there you should use the weight attribute for this edittext and button again instead of their width parameters.
A slightly modified (I couldn't keep the style and text attributes when testing, for obvious reasons) example of how your xml would look:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_weight="1"
android:baselineAligned="true" >
<LinearLayout
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1" >
<TextView
android:id="#+id/TextView08"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<EditText
android:id="#+id/eBox"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:ems="10"
android:enabled="true"
android:gravity="right"
android:inputType="number|numberSigned|numberDecimal"
android:selectAllOnFocus="true" >
</EditText>
</LinearLayout>
<LinearLayout
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:orientation="vertical"
android:layout_weight="1" >
<TextView
android:id="#+id/TextView06"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal" />
<EditText
android:id="#+id/euds"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:ems="10"
android:enabled="true"
android:gravity="right"
android:inputType="number|numberSigned|numberDecimal"
android:selectAllOnFocus="true" />
</LinearLayout>
<LinearLayout
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:orientation="vertical"
android:layout_weight="1" >
<TextView
android:id="#+id/TextView09"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|left"
android:paddingLeft="10dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingBottom="5dp" >
<EditText
android:id="#+id/etar"
android:layout_weight="0.5"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:ems="10"
android:enabled="true"
android:gravity="center_vertical|right"
android:inputType="number"
android:selectAllOnFocus="true" />
<Button
android:id="#+id/btnTarifa"
android:layout_weight="0.5"
android:layout_height="40dp"
android:layout_gravity="center_vertical|center_horizontal|center"
android:layout_marginTop="2dp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_marginLeft="5dp"
android:orientation="vertical" >
<TextView
android:id="#+id/etit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal" />
<EditText
android:id="#+id/eprice"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:ems="10"
android:enabled="true"
android:gravity="center_vertical|right"
android:inputType="numberDecimal"
android:selectAllOnFocus="true" />
</LinearLayout>
</LinearLayout>
After lot of sarch I haven't found why it happens, but a very quickly solution. I can scale all the application adding this code to the main activity:
public void changeDensity(float desiredDensity) {
//desiredDensity : ldpi = 0.75 (120dpi) , mdpi = 1 (160dpi), hdpi = 1.5 (240dpi), xhdpi = 2.0 (320dpi)
DisplayMetrics metrics = getResources().getDisplayMetrics();
metrics.density = desiredDensity;
metrics.xdpi = desiredDensity * 160;
metrics.ydpi = desiredDensity * 160;
metrics.densityDpi = (int) (desiredDensity * 160);
getResources().updateConfiguration(null, null);
}
Calling this function on creating main activity, with 1.25f as desiredDensity, the application is scaled to fit the right dimension. I know this isn't the rigth way. I should change all layout, but I can't do it with this device because both use the same layout (large) and then, perhaps, I should use w as parameter in res/layout. Briefly, scaling resolve the problem.
From this: https://stackoverflow.com/a/12077236/1616700

Center GridView horizontally [duplicate]

This question already has answers here:
Android: center gridview horizontally
(4 answers)
Closed 9 years ago.
I have a GridView with 4 items that are added dynamically. I can center them vertically but can not horizontally. Tried everything...
Main.xml
...
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_gravity="center" >
<GridView
android:id="#+id/grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:padding="10dp"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="spacingWidthUniform"
android:gravity="center"
android:listSelector="#drawable/card_button" >
</GridView>
</LinearLayout>
...
Items.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/btn"
android:layout_width="match_parent"
android:layout_height="90dp"
android:orientation="vertical"
android:gravity="center" >
<ImageButton
android:id="#+id/menuItem_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/light"
android:contentDescription="#string/item"
android:background="#00000000"
android:tint="#222222"
android:paddingTop="8dp"
android:paddingBottom="4dp" />
<TextView
android:id="#+id/menuItem_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#222222"
android:paddingBottom="8dp"
android:text="#string/item"
android:textSize="18sp"
android:singleLine="true" />
</LinearLayout>
I don't want to have fixed number of columns so android:numColumns="auto_fit" must stay.
I find out that it's not possible to center GridView horizontally with .xml
So I had to do it programmatically... This answer helped me a lot: https://stackoverflow.com/questions/6141910/android-center-gridview-horizontally
I had to make some changes to make it work:
GridView Adapter.java:
public Adapter(Context context, int width, int height, float density, GridView grid) {
this.context = context;
width_ = width; //get metrics.widthPixels from MainActivtiy.java
height_ = height; //get metrics.heightPixels from MainActivtiy.java
density_ = density; //get metrics.scaledDensity from MainActivtiy.java
grid_ = grid; //get GridView
Rect p = new Rect();
grid_.getSelector().getPadding(p);
int selectorPadding = p.left + p.right;
int mSizePx = (int) Math.floor(90 * density_); //90 is my column width
int mSpacingPx = (int) Math.floor(10 * density_); //10 is space between columns
int numColumns = (int) Math.floor(1f * (width_ - selectorPadding + mSpacingPx) / (mSizePx + mSpacingPx));
// CHANGES
int numbOfCol = menuValues.length; //menuValues (Array[]) are items you are adding to GridView
int contentWidth = 0;
//the most important part
if (numColumns > numbOfCol) {
contentWidth = numbOfCol * mSizePx;
contentWidth += (numbOfCol - 1) * mSpacingPx;
contentWidth += selectorPadding;
} else {
contentWidth = numColumns * mSizePx;
contentWidth += (numColumns - 1) * mSpacingPx;
contentWidth += selectorPadding;
}
int slack = width_ - contentWidth;
//
grid_.setNumColumns(numColumns); //set calculated number of collumns
grid_.setColumnWidth(mSizePx); //90
grid_.setVerticalSpacing(mSpacingPx); //10
grid_.setHorizontalSpacing(mSpacingPx); //10
//changed
grid_.setPadding(slack / 2, mSpacingPx, slack / 2, mSpacingPx); //I set top and bottom padding to 10dp (mSpacingPx)
}
Main.xml (changed):
...
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_gravity="center" >
<GridView
android:id="#+id/grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchMode="none"
android:gravity="center"
android:listSelector="#drawable/card_button"
android:drawSelectorOnTop="true" >
</GridView>
</LinearLayout>
...

Categories

Resources