In my application I have a conversation room. All of my messages should be aligned to right while the rest should be left aligned.
Single row of my list is like this:
<?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:id="#+id/llContainer" >
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:background="#drawable/speech_bubble_orange"
android:id="#+id/llGroup" >
<TextView
android:id="#+id/message_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:shadowColor="#color/message_textShadow"
android:shadowDx="1"
android:shadowDy="1"
android:text="Medium Text"
android:textColor="#color/message_textColor"
android:textSize="20sp" />
<TextView
android:id="#+id/message_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/temp_date"
android:gravity="right"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"/>
</LinearLayout>
</LinearLayout>
getView() of my adapter is like this:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = myInflater.inflate(R.layout.list_message_row, null);
holder = new ViewHolder();
holder.tvMessageBody = (TextView) convertView.findViewById(R.id.message_text);
holder.tvMessageDate = (TextView) convertView.findViewById(R.id.message_date);
holder.llContainer = (LinearLayout) convertView.findViewById(R.id.llContainer);
holder.llGroup = (LinearLayout) convertView.findViewById(R.id.llGroup);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvMessageBody.setText(messageList.get(position).getMessageBody());
String date = messageList.get(position).getSentDate();
holder.tvMessageDate.setText(formatFanciedDate(date));
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.llContainer.getLayoutParams();
try {
if(messageList.get(position).isMine()) {
holder.llGroup.setBackgroundResource(R.drawable.speech_bubble_green);
params.gravity = Gravity.RIGHT;
}
//If not mine then it is from sender to show orange background and align to left
else {
holder.llGroup.setBackgroundResource(R.drawable.speech_bubble_orange);
params.gravity = Gravity.LEFT;
}
holder.llContainer.setLayoutParams(params);
} catch (NullPointerException e) {
e.printStackTrace();
}
return convertView;
}
I think everything should be fine however when I run the application NullPointerException happens and points to params.gravity = Gravity.RIGHT; or params.gravity = Gravity.LEFT; (depends on isMine() method).
What you think? Where is my mistake?
Any suggestion would be appreciated.
getLayoutParams() will return null until the view is attached to its parent.
Try to create the layout params with its constructor rather than using getLayoutParams().
Use RelativeLayout params and set gravity like this, it will work.
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
This is working for me in my application.
Related
In my layout I have a TextView inside of a RelativeLayout like below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="80dp"
android:orientation="horizontal">
<TextView
android:id="#+id/textView17"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="70dp"
android:layout_marginStart="70dp"
android:layout_marginTop="12dp"
android:layout_toLeftOf="#+id/imageButton2"
android:layout_toStartOf="#+id/imageButton2"
android:text="TextView"
android:textColor="#android:color/black"
android:textSize="24sp"
android:textStyle="bold" />
The left margins are explicitly set to 70dp in this case. However, I would like to conditionally decrease the left margin to 30dp or so. My attempt to do so is here:
#Override
public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) {
final Material m = ...
ViewHolder h = (ViewHolder) holder;
h.checkedImageview.setVisibility(View.GONE);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) h.titleTextview.getLayoutParams();
layoutParams.setMargins(
20,
layoutParams.topMargin,
layoutParams.rightMargin,
layoutParams.bottomMargin
);
h.titleTextview.setLayoutParams(layoutParams);
^^ However, that is having no effect at all. If I modify the values in the XML layout, will it work without any issue? What am I doing wrong? I'm using the SectionedRecyclerViewAdapter RecyclerView library, if that matters at all.
for example :
public static class PersonViewHolder extends RecyclerView.ViewHolder {
CardView cv;
TextView personName;
TextView personAge;
ImageView personPhoto;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
personName = (TextView)itemView.findViewById(R.id.person_name);
personAge = (TextView)itemView.findViewById(R.id.person_age);
personPhoto = (ImageView)itemView.findViewById(R.id.person_photo);
}
}
so i read the git hub page justo do it :
#Override
public void onBindItemViewHolder(PersonViewHolder holder, int position) {
//here --->>>
PersonViewHolder itemHolder = (PersonViewHolder) holder; // important !
holder.checkedImageview.setVisibility(View.GONE);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) holder.titleTextview.getLayoutParams();
layoutParams.setMargins(
20,
layoutParams.topMargin,
layoutParams.rightMargin,
layoutParams.bottomMargin
);
holder.titleTextview.setLayoutParams(layoutParams);
The issue is that you're reusing the existing LayoutParams from the text view. Instead of reusing, create a new RelativeLayout.LayoutParams object, set its margins, and then set the TextView's params appropriately. Code:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams
(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, 0, 0, 0); // or any other values
textView.setLayoutParams(params);
I am trying to make a chat bubble, I have successfully did it with a text only, but when i want to add another text to put the time inside the bubble i had to add a RelativeLayout to put it on the actual linear layout, but this time i am getting an error.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:transitionGroup="true">
<RelativeLayout
android:id="#+id/my_lay"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="17sp"
android:text="test"
android:background="#drawable/sender_message_9"/>
<TextView
android:id="#+id/messageTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:text="12:12 PM"
android:layout_alignBottom="#id/message"
android:layout_alignRight="#id/message"
/>
</RelativeLayout>
</LinearLayout>
ADAPTER:
public class ChatAdapter extends ArrayAdapter<MessageProvider> {
private List<Message> list = new ArrayList<>();
private TextView TXT;
private RelativeLayout rLayout;
Context context;
...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.source_message, parent, false);
}
...
TXT.setText(Message);
//Set Linear Changes
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
if(!POSITION){ // Moves the layout to the right
params.gravity = Gravity.RIGHT;
}else { // Moves it to the Left
params.gravity = Gravity.LEFT;
}
TXT.setLayoutParams(params);
return convertView;
}
}
ERROR:
05-05 00:10:44.563 8962-8962/com.example.example E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to android.widget.RelativeLayout$LayoutParams
I would appreciate any answer, thanks.
change the following line
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
to
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
because you have included the textview inside a RelativeLayout parent.
The error is this line
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
you are using Linear layout params for a Relative Layout.
try using
RelativeLayout.LayoutParams params= new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
I'm trying to find a way to create a custom views dynamically, but I didn't find a useful post for my problem.
I have the next view.
And this is the tree of the layout:
I want to create as many copies as items received, but I need to change the textviews inside per each item.
I don't know If I have explained me well. Thank you.
EDIT:
I follow some of your advises, and I make this:
private void addInputHeader(int timestamp)
{
LinearLayout mRootLayout = (LinearLayout) findViewById(R.id.event_container);
View mChildView = getLayoutInflater().inflate(R.layout.program_event_day_header, mRootLayout, false);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mRootLayout.addView(mChildView, params);
TextView tv_day = (TextView) mChildView.findViewById(R.id.tv_day);
tv_day.setText(getDayForHeader(timestamp) + getResources().getString(R.string.of) + getMonthForHeader(timestamp));
}
private void addInputDescription(int timestamp, String description)
{
LinearLayout mRootLayout = (LinearLayout) findViewById(R.id.event_container);
View mChildView = getLayoutInflater().inflate(R.layout.program_event_day_header, mRootLayout, false);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mRootLayout.addView(mChildView, params);
TextView tv_event_hour = (TextView) mChildView.findViewById(R.id.tv_event_hour);
TextView tv_event_message = (TextView) mChildView.findViewById(R.id.tv_event_message);
tv_event_hour.setText(getHour(timestamp) + " - ");
tv_event_message.setText(description);
}
private String getDayForHeader(long timeStamp){
Date df = new Date(timeStamp*1000);
return new SimpleDateFormat("cccc dd").format(df);
}
private String getMonthForHeader(long timeStamp){
Date df = new Date(timeStamp*1000);
return new SimpleDateFormat("MM").format(df);
}
private String getHour(long timeStamp){
Date df = new Date(timeStamp*1000);
return new SimpleDateFormat("HH:mm").format(df);
}
private int getD(long timeStamp){
Date df = new Date(timeStamp*1000);
return Integer.parseInt(new SimpleDateFormat("dd").format(df));
}
private int getM(long timeStamp){
Date df = new Date(timeStamp*1000);
return Integer.parseInt(new SimpleDateFormat("MM").format(df));
}
private int getY(long timeStamp){
Date df = new Date(timeStamp*1000);
return Integer.parseInt(new SimpleDateFormat("yyyy").format(df));
}
But I'm getting a NullPointerException when the addInputDescription tries to set text on tv_event_hour.
// Add row view layout that represent ui row.xml
<?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="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/leftTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Left Top" />
<TextView
android:id="#+id/RightTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Right Top" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/leftBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Left Bottom" />
<TextView
android:id="#+id/RightBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Right Bottom" />
</LinearLayout>
</LinearLayout>
// Add view as row with msg
private void addMsg() {
View msgView = getViewWithMsg("TopLeft", "TopRight", "LeftBottom", "Right Bottom");
// msgView represent one row
// You can add it to linearlayout desendent to scrollview
}
// This method create one msg row layout and update msg
private View getViewWithMsg(String TopLeft, String TopRight, String LeftBottom,
String RightBottom) {
LayoutInflater inflator = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View root = inflator.inflate(R.layout.row, null);
TextView topLeft = (TextView) root.findViewById(R.id.leftTop);
TextView topRight = (TextView) root.findViewById(R.id.RightTop);
TextView bottomLeft = (TextView) root.findViewById(R.id.leftBottom);
TextView botomRight = (TextView) root.findViewById(R.id.RightBottom);
topLeft.setText(TopLeft);
topRight.setText(TopRight);
bottomLeft.setText(LeftBottom);
botomRight.setText(RightBottom);
return root;
}
Create an VO for your items and add it in to the layout.
Like, layout.add(item)
See the following code if you're trying to add a child view (or multiple) to your root LinearLayout:
LinearLayout mRootLayout = (LinearLayout) findViewById(R.id.ll_root);
View mChildView = getLayoutInflater().inflate(R.layout.ll_child, mRootLayout,
false);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
mRootLayout.addView(mChildView, params);
TextView tvEventHour = (TextView) mChildView.findViewById(R.id.tv_event_hour);
TextView tvEventMessage = (TextView) mChildView.findViewById(R.id.tv_event_message);
tvEventHour.setText("10:30");
tvEventMessage.setText("Fugia corum...");
Note: If the list is about to get very long you should consider using a ListView with an Adapter since this is alot better performance-wise.
You can inflate from xml:
View placeHolderView = inflater.inflate(R.layout.view_header_placeholder, mListView);
What do you mean by "change the textviews inside per each item."?
If you need the textview inside the inflated layout try this:
TextView myTextView = (TextView)placeHolderView.findViewById(R.id.my_text_view);
I have the following XML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/background"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="4dip"
android:paddingRight="4dip" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_marginLeft="4dip"
android:src="#drawable/test_imag" />
<TextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/imageView1" />
</RelativeLayout>
and the following bindView in a cursor
public void bindView(View view, Context context, Cursor cursor) {
wrapper = (RelativeLayout) view.findViewById(R.id.background);
TextView tview2 = (TextView) view.findViewById(R.id.text2);
ImageView imgview = (ImageView) view.findViewById(R.id.imageView1);
tview2.setText("Test text");
if (cursor.getPosition() % 2 == 0) {
tview2.setBackgroundResource(R.drawable.bubble_left);
} else {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
tview2.setBackgroundResource(R.drawable.bubble_right);
params.addRule(RelativeLayout.LEFT_OF, R.id.imageView1);
tview2.setLayoutParams(params);
wrapper.setGravity(Gravity.RIGHT);
}
}
I'm trying to do a bubble chat with an image, the IF part is fine, the image is on the rght side of the screen, and, the text is to the left of it.
In the else part I set the gravity to the right and add a rule to set tview2 to the left of the image.
The result of the above made the image go to the right side of the screen but the tview2 has gone, what did I do wrong?
You need to specify params for the imageview as well since you've declared it initially in the xml to be relative to the textview.
imageparams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
The result would be something like this.
else {
RelativeLayout.LayoutParams imageparams = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
imageparams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
imgview.setLayoutParams(imageparams);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
tview2.setBackgroundResource(R.drawable.bubble_right);
params.addRule(RelativeLayout.LEFT_OF, R.id.imageView1);
tview2.setLayoutParams(params);
wrapper.setGravity(Gravity.RIGHT);
}
I want to make my own custom "progress bar". I do this by drawing to linear layouts, each with a different color. After that I want to assign a width to each of them to make it look as a progress bar. The thing I am having right now:
XML file of an item of my CustomAdapter (in Gridview):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#33c2bd" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lineScore"
android:layout_width="20dp"
android:layout_height="2dp"
android:background="#eef05e"
android:paddingLeft="20dp"
android:paddingTop="0dp"
android:paddingBottom="20dp"
android:layout_below="#+id/tvLevelScore"/>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lineScoreTotal"
android:layout_width="20dp"
android:layout_height="2dp"
android:background="#0d7975"
android:paddingRight="20dp"
android:paddingTop="0dp"
android:paddingBottom="20dp"
android:layout_below="#+id/tvLevelScore"
android:layout_toRightOf="#+id/lineScore"/>
</RelativeLayout>
Then in the CustomAdapter class under the getView method I am trying to set the lineScoreTotal to 80% of the width of the item:
double viewWidth = (double) mView.getWidth();
int widthScoreBar = (int) (viewWidth * 0.8);
LinearLayout ln = (LinearLayout) mView.findViewById(R.id.lineScoreTotal);
ln.layout(0, 2, widthScoreBar, -1);
However, it is doing nothing... Am I applying the wrong code to set the width? Or is my idea of using LinearLayout to draw those "bars" maybe the wrong thing to do?
EDIT getView method:
#Override
public View getView(int position, View v, ViewGroup parent) {
View mView = v;
if (mView == null) {
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mView = vi.inflate(R.layout.levelselector_item, null);
}
TextView level = (TextView) mView.findViewById(R.id.tvLevel);
TextView levelScore = (TextView) mView.findViewById(R.id.tvLevelScore);
if (mView != null) {
level.setText(Integer.toString(getItem(position).getLevel()));
loadDataBase();
int correctAnswers = myDbHelper.getCorrectAnswers(getItem(position).getLevel());
correctAnswersPrev = 0;
correctAnswersPrev = myDbHelper.getCorrectAnswersPrev(getItem(position).getLevel());
String correct = Integer.toString(correctAnswers);
levelScore.setText(correct + "/60");
level.setTypeface(font);
levelScore.setTypeface(font);
LinearLayout ln = (LinearLayout) mView.findViewById(R.id.lineScoreTotal);
ln.setLayoutParams(new FrameLayout.LayoutParams(10, 10));
}
return mView;
}
Try either way
Without Gravity
ln.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
Or with gravity
ln.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT,1f));
ln.setLayoutParams(new
LayoutParams(widthScoreBar,LayoutParams.WRAP_CONTENT));
Try setting using LayoutParams.