I have a RecycleView in which I visualize some text. The text is entered through an EditText view in the bottom. The RecycleView contains a TextView which is has the text centered.
I have also a function that detects if the keyboard is visualised. When the keyboard is visualised, then some layout parameters are changed so that the EditText looks good. I also have a smooth scroll to the last position of the RecycleView.
When I reopen the keyboard again, the text is first drawn to the left of the screen. If I swipe, the text is re-aligned to center. That is very disturbing and I always want the text to be centered. I probably miss something when changing the parameters of the layouts.
KeyBoard openedListener:
// Function to see of keyboard is opened or not.
private void detectKeyBoard(){
final ConstraintLayout rootView = findViewById(R.id.activity_root);
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
float heightDiff = rootView.getRootView().getHeight() - rootView.getChildAt(0).getHeight();
if (!isRefSet){
refDiff = heightDiff;
isRefSet = true;
}
if (heightDiff > refDiff) {
LinearLayout.LayoutParams params = new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
0);
params.weight = wRSmall;
mRecyclerView.setLayoutParams(params);
LinearLayout.LayoutParams eParams = new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
0);
eParams.weight = wESmall;
mLinearInput.setLayoutParams(eParams);
if (mAdapter.getItemCount() > 0) {
mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount() - 1);
}
} else {
LinearLayout.LayoutParams params = new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
0);
params.weight = wRStart;
mRecyclerView.setLayoutParams(params);
LinearLayout.LayoutParams eParams = new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
0);
eParams.weight = wEStart;
mLinearInput.setLayoutParams(eParams);
if (mAdapter.getItemCount() > 0) {
mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount() - 1);
}
}
}
});
}
xml for RecycleView:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/activity_root"
tools:context="com.example.erikbylow.autoflash.TranslateActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/translate_linear"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.9"
android:scrollbars="vertical"
android:layout_gravity="center_horizontal"
android:id="#+id/translate_recycle"
android:background="#android:color/holo_blue_bright" />
<LinearLayout
android:layout_width="match_parent"
android:id="#+id/linear_input"
android:layout_height="0dp"
android:layout_weight="0.1"
android:orientation="horizontal">
<EditText
android:layout_width="0dp"
android:layout_weight="0.75"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:singleLine="true"
android:id="#+id/source_input"
android:hint="Type text to translate"/>
<Button
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="0.25"
android:layout_alignRight="#+id/source_input"
android:text="Translate"
android:clickable="true"
android:onClick="startTranslate"
android:background="#android:color/holo_green_dark"/>
</LinearLayout>
</LinearLayout>
TextView for Adapter:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:textSize="#dimen/active_text_size"
android:id="#+id/adapter_textview"/>
After swiping it is re-aligned:
EDIT: It did not work to remove android:layout_gravity="center_horizontal" in the recycle xml part.
Further, if the screen is full without the keyboard being opened, the text is moved to the right:
Can you comment the detectKeyBoard() function? Just to check if the same problem exists or not?
Just a guess -
I see that you are creating a new LayoutParams object and assign it to your mRecyclerView and mLinearInput.
As far as I know, this new LayoutParam object will replace what you have set in XML, including layout_gravity, layout_weight, etc.
Try getting existing LayoutParams from mRecyclerView and mLinearInput, and modify their values instead.
Cannot advise much because I do not really understand the reason behind resetting layout params in your case.
Related
I have a slight problem getting my layout_weight to work. I am creating a custom bottomBar. But i cant make it to stretch as i want it to.
Bottom Bar View
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/bottom_bar_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/bottom_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="4"
android:orientation="horizontal"/>
</RelativeLayout>
This is the big container i am adding my buttons (items) to.
Bottom Bar Item
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<android.support.v7.widget.AppCompatImageView
android:id="#+id/bottom_bar_item_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#android:drawable/arrow_up_float"/>
<TextView
android:id="#+id/bottom_bar_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TEXT"/>
</LinearLayout>
This is my items that i add dynamically to the view. But somehow the view is not stretched properly.
But when i hardcode it in. It works. So could it be that layout weight does not work dynamically?
How i add the views (items)
private void updateItems(final List<BottomBarTab> bottomBarTabs) {
if (bottomBarTabs.size() < TABS_COUNT) {
throw new RuntimeException("Not enough buttons for bottomBar");
}
for (int i = 0; i < TABS_COUNT; i++) {
bottomBarTabs.get(i).setOnClickListener(this);
bottomBarTabs.get(i).prepareLayout();
container.addView(bottomBarTabs.get(i));
}
}
Screenshot
LayoutWeight is given to inner components of layout only not on parent Linearlayout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="match_parent"
android:weightSum="2">
<android.support.v7.widget.AppCompatImageView
android:id="#+id/bottom_bar_item_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="#android:drawable/arrow_up_float"/>
<TextView
android:id="#+id/bottom_bar_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TEXT"/>
</LinearLayout>
public void prepareLayout() {
View view = inflate(getContext(), R.layout.bottom_bar_item,this);
LinearLayout.LayoutParams params =
new LayoutParams(0,LayoutParams.MATCH_PARENT,LAYOUT_WEIGHT);
view.setLayoutParams(params);
if(backgroundColor != null) {
view.setBackgroundColor(backgroundColor);
}
TextView titleText = (TextView) view.findViewById(R.id.bottom_bar_item_text);
titleText.setText(title);
AppCompatImageView imageView = (AppCompatImageView) view.findViewById(R.id.bottom_bar_item_icon);
imageView.setImageResource(iconResId);
}
I changed in my prepareLayout function and put new layoutParams. Because somehow after inflation. The view ignores the weight that was set to it. So i had to force it by code. Maybe this is a android bug?
I am creating a TextView dynamically. Here, I am creating a mainLayout in which I have two child layout and I wan gave them weight.
Here, is my Layout
<?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">
<LinearLayout
android:baselineAligned="false"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/Layout_second_overs"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="6"
android:orientation="vertical">
<!--Second textview overs-->
</LinearLayout>
<LinearLayout
android:id="#+id/Layout_second_balls"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:orientation="horizontal">
<!--Second textview balls--> //here i inflate 12 textview dynamically but not 12 seen on the device while i run the app.
</LinearLayout>
</LinearLayout>
</LinearLayout>
Code to create a 12 TextViews and put into layout.
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
for(int a = 0; a <= 12; a++)
{
TextView first = new TextView(getApplicationContext());
first.setLayoutParams(params);
first.setTextColor(Color.parseColor("#000000"));
first.setTextSize(12);
first.setGravity(Gravity.LEFT);
first.setPadding(5, 0, 5, 0);
first.setText("12");
layout_second_balls.addView(first); //This is my linear layout which id is Layout_second_balls
}
Problem is my all data are print into log but not visible on the device.
Please, help me to solve out this problem.
There are two issues
One is for the Layout Design related
Second based on the layout design and property you also need to
handle is while you are adding dynamically view into linear layout
Here what i have changed in Your xml file
<?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">
<LinearLayout
android:baselineAligned="false"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/Layout_second_overs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<!--Second textview overs-->
</LinearLayout>
<LinearLayout
android:id="#+id/Layout_second_balls"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1" android:background="#FF13C7FF"
android:orientation="horizontal">
</LinearLayout>
</LinearLayout>
</LinearLayout>
In Layout_second_overs linearlayout height , Width & weight is the issue.
& in Layout_second_balls linear layout you have used weight as 1 so you also required layout_height as 0dp if orientation is horizontal
Now below things i have changed in code
LinearLayout.LayoutParams params = new
LinearLayout.LayoutParams
(0, LinearLayout.LayoutParams.WRAP_CONTENT);
for(int a = 0;a<=12;a++)
{
TextView first = new TextView(getActivity());
first.setLayoutParams(params);
first.setTextColor(Color.parseColor("#000000"));
first.setTextSize(12);
params.weight = 1; /// Need to give weight if you want equal size of textview inside Linear
first.setGravity(Gravity.LEFT);
first.setPadding(5, 0, 5, 0);
first.setText("12");
Layout_second_balls.addView(first); //This is my linear layout which id is Layout_second_balls
}
above things are based on the question which you ask
Suggestion
Avoid adding dynamic view like you asked . prefer to use ListView, GridView, RecyclerView for this type of functionality.
Your layout_second_overs requires all of your screen space - so your layout_second_balls is moved out of your screen.
If you want to see your two LinearLayouts beside each other, you need to set the layout_width to "0dp":
//pseudo, simply change width to 0dp
<LinearLayout
android:layout_height="40dp"
.... >
<LinearLayout
android:layout_width="0dp"
android:layout_weight="6"/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"/>
</LinearLayout>
To replace this kind of loops you are supposed to use a RecyclerView. It is easy to use and responsive (since your list will be scrollable).
The things you have to remember while implementing a RecyclerView are to add an adapter and a LayoutManager to it.
For your example :
LayoutManager manager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, true);
YourAdapter adapter = new YourAdapter([...]);
RecyclerView recyclerView = findViewById(R.id.your_recyclerview_here);
recyclerView.setLayoutManager(manager);
recyclerView.setAdapter(adapter);
If you need any advices for creating your adapter just ask.
You can use this line of code.
LinearLayout layout_second_balls=(LinearLayout) findViewById(R.id.Layout_second_balls);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
for(int a = 0;a<=12;a++)
{
TextView first = new TextView(getApplicationContext());
first.setLayoutParams(params);
first.setTextColor(Color.parseColor("#000000"));
first.setTextSize(12);
first.setGravity(Gravity.LEFT);
first.setPadding(5, 0, 5, 0);
first.setText("12");
layout_second_balls.addView(first);
}
i run this code in my emulator and i got this out put.
You have to assign index for a view while performing addview(view,index) set index for each textview created in for loop like layout_second_balls.addView(first,index);
Code should look like :
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
for(int a = 0; a <= 12; a++)
{
TextView first = new TextView(getApplicationContext());
first.setLayoutParams(params);
first.setTextColor(Color.parseColor("#000000"));
first.setTextSize(12);
first.setGravity(Gravity.LEFT);
first.setPadding(5, 0, 5, 0);
first.setText("12");
layout_second_balls.addView(first,a);
}
Hope it will work.
I set up a simple activity to try to boil down this problem.
I have a FrameLayout in which I have enabled "AnimateLayoutchanges".
I have a button which onclick changes the layout margin and width of a TextView.
If this is the only layout change, the change in margin and width will NOT get animated. However, if I simple set the visibility if another child of the same FrameLayout, both the visibility change AND the margin/width change will animate.
Side note: the visibility and margin+width change will happen in sequence as opposed to simultaneously, is there a way to change this behavior?
<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"
android:background="#888"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".activities.TestActivity">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/PivotTheme" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="buttonHandler"
android:text="test button 1" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="#color/white">
<TextView
android:id="#+id/testTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/purple_gradient_end"
android:text="TestView" />
<TextView
android:id="#+id/testTv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="#color/purple_gradient_end"
android:text="TestView" />
</FrameLayout>
</LinearLayout>
Activity:
public void buttonHandler(View view){
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) testTv.getLayoutParams();
if(testDown) {
params.setMargins(100, 400, 0, 0);
params.width = 400;
testTv2.setVisibility(View.GONE);// if I comment out this line, nothing will animate
testDown = false;
} else {
params.setMargins(0, 0, 0, 0);
params.width = 100;
testTv2.setVisibility(View.VISIBLE);
testDown = true;
}
testTv.setLayoutParams(params);
}
I feel like this is a bug with android where changes in margin or width are failing to set a flag to trigger animation, but if this flag is set by changing visibility, then all the animations are properly handled.
for that type of changing..like change param..you need to enable 'changing' too (animateLayoutChange must be true)
val frmMain=findViewById<FrameLayout>(R.id.frmMain)
val currentTransitions=frmMain.layoutTransition
currentTransitions.enableTransitionType(LayoutTransition.CHANGING)
frmMain.layoutTransition=currentTransitions
I am creating a chat application in which i need to align the chat messages accordingly.I need to align those from the user to right side and others to the left side.I have a listview in which the messages are displayed.For now,i am using bundled json for getting data.Here is my code
This is for appending a string to the message typed by the user which is checked and splitted inorder to recognize messages from the user.
final EditText et = (EditText)findViewById(R.id.EditText1);
final Button imb=(Button)findViewById(R.id.btn_send);
imb.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View arg0)
{
String str = et.getText().toString()+":aeiou";
web.add(str);
scrollMyListViewToBottom();
et.setText(" ");
adapter.notifyDataSetChanged();
}
After that, i am splitting the string and stored in an array.If the message is from user.ie,if it has the appended string,then the gravity of the layout need to be set to RIGHT,else LEFT.
I used this code in my adapter class for this
mychat=web.get(position);
if(mychat.contains(":"))
{
String[] splitted = mychat.split(":");
String chats;
if(splitted[1].equalsIgnoreCase("aeiou"))
{
chats=splitted[0];
Toast.makeText(context, "You entered...."+chats, Toast.LENGTH_SHORT).show();
LinearLayout my_layout = (LinearLayout) rowView.findViewById(R.id.main_layout);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.RIGHT;
my_layout.setLayoutParams(params);
//my_layout.setGravity(Gravity.RIGHT);
txtTitle.setText(chats);
}
}
else
{
txtTitle.setText(web.get(position));
}
txtTitle.setBackgroundResource(R.drawable.test);
What is wrong in this ?Please help...
Here is my xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#2a2a34"
android:padding="3dp"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:id="#+id/chat_icon_layout"
android:layout_width="match_parent"
android:layout_weight="4"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/img"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/white" />
<ImageView
android:id="#+id/img1"
android:layout_width="55dp"
android:layout_height="55dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/abs__ab_bottom_solid_light_holo" />
</RelativeLayout>
<LinearLayout
android:id="#+id/chat_text_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="0dp"
android:layout_weight="1" >
<TextView
android:id="#+id/txt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Message"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#ffffff" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
since you want to align chat messages to left and right therefore you need to align your text messages i.e your text view. therefore you need to do
if(...)
txtTitle.setText(chats);
txtTitle.setGravity(Gravity.RIGHT);
}
}
else
{
txtTitle.setText(web.get(position));
txtTitle.setGravity(Gravity.LEFT);
}
In your adapter, you should be setting the other case in else condition as well. Example is below.
I saw you are using wrap_content for your width. So your LinearLayout will wrap your content and can't align to left or right of your layout. You should use fill parent for your LinearLayout in order it to align it's contents if there is sufficient space
if(splitted[1].equalsIgnoreCase("aeiou"))
{
chats=splitted[0];
Toast.makeText(context, "You entered...."+chats, Toast.LENGTH_SHORT).show();
LinearLayout my_layout = (LinearLayout) rowView.findViewById(R.id.main_layout);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.RIGHT;
my_layout.setLayoutParams(params);
//my_layout.setGravity(Gravity.RIGHT);
txtTitle.setText(chats);
}
}
else{
LinearLayout my_layout = (LinearLayout)rowView.findViewById(R.id.main_layout);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.LEFT;
my_layout.setLayoutParams(params);
txtTitle.setText(web.get(position));
}
The problem is you are setting the layout gravity right.. try setting the textview gravity left or right..
just add the property in the xml android:gravity="left" or android:gravity="right"
I have the following layout
<?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="match_parent"
android:orientation="horizontal"
android:background="#f00"
android:id="#+id/main_layout">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#0f0"
android:id="#+id/bed_list"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00f"
android:text="Howdy cowboy?"
android:textSize="50dip"
android:textColor="#fff"
android:id="#+id/textview"/>
</LinearLayout>
I want to add some textviews to R.id.bed_list (as if they were vertical tabs)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
LinearLayout bedList = (LinearLayout) findViewById(R.id.bed_list);
for (int i = 0; i < 12; i++) {
System.out.println("In the loop");
TextView textView = new TextView(this);
textView.setText("HJM-" + i);
textView.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
textView.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
bedList.addView(textView,i,
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
}
}
So far, the code is run, the System.out.println messages in the loop appear at the console, but I only see the textview (R.id.textview). I wanted the list to appear at the left of the screen with the options calculated, but it does not work.
Further on, if I define a first textview in the label (so that there is some items at the very beginning and a space is reserved), I get to see that textview but the others (added from the program) do not appear either.
Your textview (R.id.textview) has a width of match_parent, effectively pushing your other views (the linearlayout) off screen. Instead you can give it a width of wrap_content and possibly a layout_weight of 1.