How to relayout RecyclerView after IME candidates is hidden? - android

I'm trying to make a chat-like screen with RecyclerView as this
However RecyclerView (LinearLayoutManager) doesn't works as I expected...
How can I fix or avoid this problem?
Detail:
The problem is also reproducible with very simplified Activity shown below.
activity_main.xml
<?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.support.v7.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:scrollbars="none"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeRecyclerView();
}
private void initializeRecyclerView() {
RecyclerView recycler = (RecyclerView) findViewById(R.id.recyclerview);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setReverseLayout(true);
recycler.setLayoutManager(layoutManager);
Adapter recyclerAdapter = new Adapter(createItemList());
recycler.setAdapter(recyclerAdapter);
}
private static ArrayList<String> createItemList(){
ArrayList<String> items= new ArrayList<>();
for(int i=0;i<20;i++){
items.add(String.format("item %02d",20-i));
}
return items;
}
}
RecyclerView is not completely relayout after IME candidates are hidden shown in this movie.
This problem is fixed by adding "adjustResize" into MainActivity's windowSoftInputMode, but I don't want to use it. Solution without changing windowSoftInputMode is wanted.

I had a similar problem. What will help you is creating a custom adapter which has a different viewholder and onbindview for the IME candidates. Then you can easily hide the IME candidates by changing LayoutView.Params and setting height to zero. This is how I've done it, sounds like a workaround but works for me. Hope this helps.

Related

Recyclerview opens with the middle item and not from the top

This is my fragment where I have called the recycler view:
public class sgpa_frag extends Fragment {
//View view;
RecyclerView recyclerview;
adapter_sgpa ac;
ArrayList<POJO> sgpaArrayList;
public sgpa_frag() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_sgpa_frag, container, false);
recyclerview= (RecyclerView) view.findViewById(R.id.rc1);
sgpaArrayList= new ArrayList<>();
ac= new adapter_sgpa(sgpaArrayList);
recyclerview.setLayoutManager(new LinearLayoutManager(getContext(),RecyclerView.VERTICAL,true));
recyclerview.setAdapter(ac);
Fetchdata1();
return view;
}
private void Fetchdata1()
{
dbmanager db= new dbmanager(getContext());
Cursor cursor= db.fetch_data1();
if (cursor!= null){
// cursor.moveToFirst();
while (cursor.moveToNext()){
POJO pj= new POJO();
pj.setSname(cursor.getString(0));
pj.setSemester(cursor.getString(1));
pj.setSgpa(cursor.getString(2));
pj.setPercent(cursor.getString(3));
pj.setSchemes(cursor.getString(4));
sgpaArrayList.add(pj);
}
ac= new adapter_sgpa(sgpaArrayList);
}
}
}
This is my xml file:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:context=".drawernav.bottom_navi.recycler_view.sgpa_frag">
<!-- TODO: Update blank fragment layout -->
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rc1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="60dp">
</androidx.recyclerview.widget.RecyclerView>
</FrameLayout>
I want my Recycler view to start displaying from the top item and not from the middle item . Can anyone tell me what changes should I make in my code ? Thanks in advance .
I mean to say that, it is like this:
And I want it to be like this:
You should set layout width and height of the recyclerview to match_parent.
The actual reason for your issue is probably the reverseLayout of your your linear layout manager. This has the effect as scrolling down the recyclerview.
Use this instead:
new LinearLayoutManager(getContext(),RecyclerView.VERTICAL,false)
Try adding
android:descendantFocusability="blocksDescendants"
to the recyclerview parent layout
Edit:
I think it is not a problem with RecyclerView instead if you are using a cordinator layout as root layout, try giving margin to your FrameLayout of 60
<!-- TODO: Update blank fragment layout -->
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rc1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop ="60dp" //approx for toolbar height
android:paddingBottom="60dp">
</androidx.recyclerview.widget.RecyclerView>
Add this into you code
mRecyclerView.smoothScrollToPosition(0);

RecyclerView contents in NestedScrollView disappears after been scrolled out of view

I have a Recyclerview in a Nestedscrollview.It shows very well on loading showing all the contents of my customadapter but on scrolling some items away from sight and scrolling it back to them,the textviews will be gone.But imageviews doesnt behave like this.I have the Recyclerview in my Activity onCreate implemented this way
styles=response.body();
adapter=new DesignerStylesAdapter(styles);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(DesignerActivity.this,RecyclerView.HORIZONTAL,false);
mLayoutManager.setAutoMeasureEnabled(true);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setAdapter(adapter);
and in activity layout file
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:behavior_overlapTop="52dp"
android:fillViewport="true"
android:id="#+id/nestedscrollview"
app:layout_behavior="#string/appbar_scrolling_view_behavior" >
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:scrollbars="vertical"
android:layout_below="#+id/line"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v4.widget.NestedScrollView>
and in my custom adapter's onBindViewHolder,Im not calling setVisibility on any view
#Override
public void onBindViewHolder(final ViewHolder holder,final int position){
final Context context = holder.productPic.getContext();
final CustomStyles style=styles.get(position);
holder.productName.setText(style.getName());
holder.productPrice.setText("₦"+ NumberFormat.getNumberInstance(Locale.US).format(style.getCustomPrice()));
Picasso.with(context)
.load(style.getPhoto1())
.into(holder.productPic);
}
Someone kindly help out,Ive been stuck on this issue for the whole day.

CoordinatorLayout/AppBarLayout interfere with RecyclerView scrollToPosition(bottom scrolling)

This question has been asked many times but it just doesn't seem to have a solution that fits my requirement.
I have a Recipe that has instructions. Each instruction is ordered in a RecyclerView. The order must be from top to bottom. It cannot be reversed like many answers to this question.
I have an Add button that when clicked a new item is added at the bottom of the list. I need to scroll to the new item after the insert. So I employed the following code in the button's onClick event:
mRecyclerAdapter.addItem(newInstruction);
mRecyclerView.smoothScrollToPosition(mRecyclerAdapter.getItemCount() - 1);
This scrolls to the second last item because in the adapter's addItem() method I have this:
mItems.add(item);
notifyItemInserted(getItemCount() - 1);
I don't know the details of the notifyItemInserted() call, but it appears to be on a separate thread, which means that smoothScrollToPosition() is called before the views have been laid out after the insertion. Hence, it only scrolls to the second last item.
I have tried looking for a "callback" function along the lines of onItemInserted but I did not have any luck. eg, no answer Here.
How do I solve this problem?
EDIT START
I've simplified the code in a new project in hope to find the problem, and found out what the problem is. It appears to be a problem caused by CoordinatorLayout/AppBarLayout when scrolling flag is enabled. It seems as though the scrolling did not take into consideration the extra scrolling space added by the AppBarLayout.
In the sample codes below, if you disable the scrolling flag for the app bar, scrolling to the bottom of the screen works perfectly as intended. However, if you enable the AppBarLayout scrolling behavior, and change its height, you'll notice that scrolling to the bottom is off by the given height.
I need the scrolling behavior, so how do I make them play nicely with each other? Please note that I've changed the question to reflect the problem.
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final int ITEMS_COUNT = 50;
private FloatingActionButton mFloatingActionButton;
private RecyclerView mRecyclerView;
private RecyclerAdapter mRecyclerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFloatingActionButton = (FloatingActionButton) findViewById(R.id.fabButton);
mFloatingActionButton.setOnClickListener(this);
setupRecyclerView();
}
private void setupRecyclerView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerAdapter = new RecyclerAdapter(createItemList());
mRecyclerView.setAdapter(mRecyclerAdapter);
}
private List<String> createItemList() {
List<String> itemList = new ArrayList<>();
for (int i = 0; i < ITEMS_COUNT; i++) {
itemList.add("Item " + i);
}
return itemList;
}
#Override
public void onClick(View v) {
mRecyclerView.scrollToPosition(49);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- changing the height affects the scrolling distance -->
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Header"
app:layout_scrollFlags="scroll|enterAlways"/> <!-- this is the problem -->
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fabButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="20dp"/>
</android.support.design.widget.CoordinatorLayout>
RecyclerAdapter.java
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<String> mItemList;
public RecyclerAdapter(List<String> itemList) {
mItemList = itemList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
View view = LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false);
return RecyclerItemViewHolder.newInstance(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
RecyclerItemViewHolder holder = (RecyclerItemViewHolder) viewHolder;
String itemText = mItemList.get(position);
holder.setItemText(itemText);
}
#Override
public int getItemCount() {
return mItemList == null ? 0 : mItemList.size();
}
}
recycler_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
card_view:cardCornerRadius="4dp">
<TextView
android:id="#+id/itemTextView"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:padding="8dp"
style="#style/Base.TextAppearance.AppCompat.Body2"/>
</android.support.v7.widget.CardView>
EDIT END
Doing a bit more research I found this question/answer which has a workaround to this problem. Although not ideal, it will have to do for now. Though the real solution shouldn't have to collapse the AppBarLayout, the scrolling should take into consideration the extra scrolling space needed. Perhaps this is just a bug that is overlooked.
In your addItem() method change this
notifyItemInserted(getItemCount() - 1);
to
notifyItemInserted(mItems.size() - 1);
This will solve the problem!
add this after adding item
notifyItemRangeChanged(0, items.size());
Have you tried
mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());
You can also put it in a runnable like this to make sure item has added before you scroll to it.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());
}
}, 1000);
Before you add list to adapter in Recycleview do some sorting by using Collection method according to your need,use this code may help you
Comparator<Long> comparator = Collections.reverseOrder();
Collections.sort(arrayList, comparator);

RECYCLERVIEW SPACE BETWEEN ITEMS ON ANDROID APPLICATION

I have a project i am developing but i have come to face a problem with a large gap appearing between two items on my android application ,i had tried to look on every previous suggestions here on how to solve the problem but none has worked for me
Here is my Layout that causes problems
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:layout_height="match_parent"
android:orientation="horizontal">
<android.support.v7.widget.RecyclerView
android:id="#+id/prodct_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="false"
android:scaleType="fitXY"
android:padding="0dp"
android:adjustViewBounds="true"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/actionbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_gravity="end"
android:visibility="gone" />
And here is my oncreate method on activity associated with the above layout:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tabletSize = getResources().getBoolean(R.bool.isTablet);
if (!tabletSize) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
setContentView(R.layout.order_details);
ab = getSupportActionBar();
ab.setDisplayUseLogoEnabled(true);
ab.setDisplayHomeAsUpEnabled(true);
actionButton = (FloatingActionButton) findViewById(R.id.actionbutton);
actionButton.setBackgroundColor(getResources().getColor(R.color.actionbar));
actionButton.setImageResource(R.drawable.ic_action_send);
appPreference = new AppPreference(this);
mRecyclerView = (RecyclerView) findViewById(R.id.prodct_list);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
final Intent intent = getIntent();
pyid = intent.getExtras().getLong(Quotes.ID);
mItemsDetail = QuoteItems.getItemsArray(this ,pyid);
mAdapter = new DeliveryDetailsAdapter(this, mItemsDetail);
mRecyclerView.setAdapter(mAdapter);
pContent = new ParseContent(this);
title = intent.getExtras().getString(Quotes.REFERENCE);
if (pyid == 0)
finish();
if (Validating.areSet(title))
ab.setTitle("Quote Details");
else
ab.setTitle(getString(R.string.strorder));
mRecyclerView.addOnItemTouchListener(
new RecylerItemClick(this, new RecylerItemClick.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
}
})
);
And here is my list of items populated on recyclerview:
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view11"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/rltotals"
android:layout_below="#+id/autotxtsaleclientname"
card_view:cardBackgroundColor="#color/white"
card_view:cardCornerRadius="7.0dip"
card_view:cardElevation="0dp">
<android.support.v7.widget.RecyclerView
android:id="#+id/prodct_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:scrollbars="vertical" />
</android.support.v7.widget.CardView>
And when i run the application on that part the items on recyclerview displays with large gap between each item
Can anyone help me to solve the issue with the gap between the items
The problem is with your adapter class. You need to make the adapter class parent height as wrap_content. Since your recylerview is vertical, you need to change the height of the adapter parent layout to wrap_content. After that also if the problem exists check whether any other adapter child view height is match_parent, if so change that to wrap_content.
Hope this is Helpful :)
check the item layout inside DeliveryDetailsAdapter for inflating each item (OncreateViewholder)
You may have given some margin in root layout. remove margin from root layout and set width as match parent and height as wrap_content

RecylcerView scrolls to Top on Item Removed

I use the following Code in my RecyclerView.Adapter to remove an Item. If the current scroll-position is at the top, everything works fine.
If the scroll-position is somewhere in the middle of the List, the List automatically scrolls to the Top of the View.
How to avoid this behaviour?
public class MyAdapter extends RecyclerView.Adapter {
...
public void removeItem(int pos){
mDataset.remove(pos); //List with Items
notifyItemRemoved(pos);
notifyItemRangeChanged(pos,mDataset.size());
}
}
<FrameLayout
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">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
...
</FrameLayout>
Adding the following Line solved it for me
recyclerView.setHasFixedSize(true);
for recycler view you use
yourRecylerView.scrollToPosition(position);
Just check whether this position is present in the list.
Use this :
mDataset.remove(pos);
adapter.notifyItemRemoved(pos);
adapter.notifyDataSetChanged();
You need to scroll to the position removed after notifying the dataset associated with the RecyclerView is changed.
And yes, you just have to call notifyDataSetChanged() after removing an item from the mDataset. So your adapter will look like this.
public class MyAdapter extends RecyclerView.Adapter {
//... Code goes here
public void removeItem(int pos){
mDataset.remove(pos);
notifyDataSetChanged();
recyclerView.scrollToPosition(pos - 1);
}
}
Try this
mDataset.remove(pos);
adapter.notifyItemRemoved(pos);
adapter.notifyDataSetChanged();
This should work.
Try this code:
public void removeItem(int position){
mdata.remove(position);
notifyItemRangeChanged(position,mdata.size());
}
I use recyclerView inside nestedScrollView and had the same issue. Here is the code to call to remove an item
mDataset.remove(pos) // Remove from dataset
notifyItemRemoved(pos) // Show animation of removing
And here are lines to be added to XML to make it scroll correctly (RecyclerView is focused with higher priority than its viewHolders so it won't scroll)
android:descendantFocusability="beforeDescendants"
android:nestedScrollingEnabled="false"
After that everything was ok.

Categories

Resources