I use typical AppBarLayout-CollapsingToolbarLayout-Toolbar bundle, and it works ok. But when I add app:expanded="false" or appBarLayout.setExpanded(false) before collapsingToolbarLayout.setTitle(), I have behavior shown in video below.
https://youtu.be/OgSJomzYmek
Here is layout:
<?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/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:expanded="false"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="#+id/action_bar_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="#drawable/img_nature"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:backgroundTint="#color/colorPrimary"
app:layout_anchorGravity="bottom|right|end" />
</android.support.design.widget.CoordinatorLayout>
It must be bug in support library.
Is there solution to correctly collapse toolbar, or any workaround?
Update 1.
Have found "solution". In short:
Override CollapsingToolbarLayout onLayout
onLayout(changed, ...) {
if (changed) super.onLayout(true, ...);
}
Nothing more to override. Than use this custom CollapsingToolbarLayout instead of from support library one.
Do not understand why, but this is necessary.
In Activity
appBarLayout.post(... here first call of appBarLayout.setCollapsed() ... )
Do not use AppBarLayout until it completely measured and laid out.
Update 2.
Update 1 not works perfectly. Much better solution - works ok, at least for a while:
Another solution, seems works perfect, at least for a while...
public class Toolbar extends android.support.v7.widget.Toolbar {
private Integer offset = null;
public Toolbar(Context context) {
super(context);
}
public Toolbar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Toolbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void offsetTopAndBottom(int offset) {
super.offsetTopAndBottom(offset);
if (this.offset == null)
this.offset = offset;
}
#Override
public int getTitleMarginTop() {
return offset == null ? super.getTitleMarginTop() : -getTop() + offset + super.getTitleMarginTop();
}
#Override
public int getTitleMarginBottom() {
return offset == null ? super.getTitleMarginBottom() : getTop() - offset + super.getTitleMarginBottom();
}
}
That's all.
When ABL's setExpanded is called, it follows to CTL's onLayout: getDescendantRect and then mCollapsingTextHelper.setCollapsedBounds.
At this moment getDescendantRect calculates base absolute position for title. And calculated position, I suppose, has error - it's shifted on (CTL height - Window inset - Toolbar height). The code above corrects this error.
Related
In Xamarin Forms we can set the TextCell property like this right?
<ListView x:Name="WorkersListView" BackgroundColor="#ECEFF1" Margin="2" ItemSelected="WorkersListView_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell TextColor="Black" Text="{Binding WorkerName}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
By writing ListView.ItemTemplate and DataTemplate we can access the TextCell
But how can i do it on Xamarin Android?
because it doesn't have ListView.ItemTemplate and DataTemplate elements.
This is my current ListView in my Xamarin.Android project
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/WorkersListView"
android:background="#android:color/darker_gray"
android:layout_margin="2dp">
</ListView>
Thanks in advance.
Working with ListView in Xamarin Forms and Xamarin Android is different
Add an XML that looks something like this:
<?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">
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fastScrollEnabled="true" />
</LinearLayout>
Then create ListView template
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:minWidth="25px"
android:minHeight="25px"
android:paddingBottom="4dp">
<ImageView
android:id="#+id/photoImageView"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:padding="5dp" />
<TextView
android:id="#+id/nameTextView"
android:layout_toRightOf="#id/photoImageView"
android:text="Name"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp" />
<TextView
android:id="#+id/departmentTextView"
android:layout_toRightOf="#id/photoImageView"
android:layout_below="#id/nameTextView"
android:text="Department"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp" />
</RelativeLayout>
Create an adapter class something like:
public class MyCustomListAdapter : BaseAdapter<User>
{
List<User> users;
public MyCustomListAdapter(List<User> users)
{
this.users = users;
}
public override User this[int position]
{
get
{
return users[position];
}
}
public override int Count
{
get
{
return users.Count;
}
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var view = convertView;
if(view==null)
{
view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.userRow, parent, false);
var photo = view.FindViewById<ImageView>(Resource.Id.photoImageView);
var name = view.FindViewById<TextView>(Resource.Id.nameTextView);
var department = view.FindViewById<TextView>(Resource.Id.departmentTextView);
view.Tag = new ViewHolder() { Photo = photo, Name = name, Department = department };
}
var holder = (ViewHolder)view.Tag;
holder.Photo.SetImageDrawable(ImageManager.Get(parent.Context, users[position].ImageUrl));
holder.Name.Text = users[position].Name;
holder.Department.Text = users[position].Department;
return view;
}
}
A detailed answer is in the blog:
https://www.c-sharpcorner.com/article/creating-custom-listview-in-xamarin-android-app/
ListView in Android instance requires an Adapter to consume the data contained in row Views.
Add one ListView and one TextView control, to display the list of items and the elements respectively. Use the following code.
<?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:background="#6BC6ED"
>
<TextView
android:id="#+id/Name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="25dp"
android:textColor="#FFFFFF"
/>
<ListView
android:id="#+id/demolist"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
Similar to what we did in Forms , create new model class which contains the binding property in ViewCell.
For example
public class Students {
public string Name {
get;
set;
}
public int Age {
get;
set;
}
}
Next, you need to create Adapter to bind the data to the ListView. Android has in-built base adapter class for Adapter implementations to bind a ListView to a data source. Also, we can get item position, count, and selected item, etc. there. Count method is used to get the number of rows in the list.
GetView method is used to return a View for each row, populated with which element.
GetItemId method is used to return row data properties like row number and value.
public class StudentAdapter: BaseAdapter < Students > {
public List < Students > sList;
private Context sContext;
public StudentAdapter(Context context, List < Students > list) {
sList = list;
sContext = context;
}
public override Students this[int position] {
get {
return sList[position];
}
}
public override int Count {
get {
return sList.Count;
}
}
public override long GetItemId(int position) {
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent) {
View row = convertView;
try {
if (row == null) {
row = LayoutInflater.From(sContext).Inflate(Resource.Layout.Main, null, false);
}
TextView txtName = row.FindViewById < TextView > (Resource.Id.Name);
txtName.Text = sList[position].Name;
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine(ex.Message);
} finally {}
return row;
}
}
Next, open your activity file and write the below code to create a list of items to display a ListView and show the selected items from the list.
private ListView studentlistView;
private List < Students > mlist;
StudentAdapter adapter;
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
List < Students > objstud = new List < Students > ();
objstud.Add(new Students {
Name = "Jack", Age = 26
});
objstud.Add(new Students {
Name = "Mary", Age = 26
});
studentlistView = FindViewById < ListView > (Resource.Id.demolist);
mlist = new List < Students > ();
mlist = objstud;
adapter = new StudentAdapter(this, mlist);
studentlistView.Adapter = adapter;
studentlistView.ItemClick += StudentlistView_ItemClick;
}
To handle the selected items, write the below code.
private void StudentlistView_ItemClick(object sender, AdapterView.ItemClickEventArgs e) {
var select = mlist[e.Position].Name;
Android.Widget.Toast.MakeText(this, select, Android.Widget.ToastLength.Long).Show();
}
For more details you can check here .
In my application, I have a ListView to contain the 5 quiz questions and their answers from a json file in server. I want the choices to be Radio Buttons but when my application runs on the emulator, I can see the questions and answers but after clicking one of the radio buttons, some other questions' answers Radio Buttons are checked. How can I prevent that?
Here is my adapter class:
public class FormSoruAdapter extends ArrayAdapter<FormSoru>{
List<FormSoru> formSoruList;
Context context;
private LayoutInflater mInflater;
//Constructor method
public FormSoruAdapter(Context context, List<FormSoru> objects){
super(context, 0, objects);
this.context = context;
this.mInflater = LayoutInflater.from(context);
formSoruList = objects;
}
#Override
public FormSoru getItem(int position){
return formSoruList.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
final ViewHolder vh;
if (convertView == null){
View view = mInflater.inflate(R.layout.list_soru,parent,false);
vh = ViewHolder.create((LinearLayout) view);
view.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
FormSoru item = getItem(position);
vh.textViewSoruNo.setText(item.getId());
vh.textViewSoru.setText(item.getSoru());
String cevap1 = item.getCevap1();
String cevap2 = item.getCevap2();
String cevap3 = item.getCevap3();
String cevap4 = item.getCevap4();
String cevap5 = item.getCevap5();
if (cevap1 == "" && cevap2 == "" && cevap3 == "" && cevap4 == "" && cevap5 == ""){
vh.radioButtonCevap1.setVisibility(View.GONE);
vh.radioButtonCevap2.setVisibility(View.GONE);
vh.radioButtonCevap3.setVisibility(View.GONE);
vh.radioButtonCevap4.setVisibility(View.GONE);
vh.radioButtonCevap5.setVisibility(View.GONE);
} else {
vh.radioButtonCevap1.setText(item.getCevap1());
vh.radioButtonCevap2.setText(item.getCevap2());
vh.radioButtonCevap3.setText(item.getCevap3());
vh.radioButtonCevap4.setText(item.getCevap4());
vh.radioButtonCevap5.setText(item.getCevap5());
}
return vh.rootView;
}
private static class ViewHolder {
public final LinearLayout rootView;
public final TextView textViewSoruNo;
public final TextView textViewSoru;
public final RadioButton radioButtonCevap1;
public final RadioButton radioButtonCevap2;
public final RadioButton radioButtonCevap3;
public final RadioButton radioButtonCevap4;
public final RadioButton radioButtonCevap5;
private ViewHolder(LinearLayout rootView, TextView textViewSoruNo, TextView textViewSoru, RadioButton radioButtonCevap1, RadioButton radioButtonCevap2, RadioButton radioButtonCevap3, RadioButton radioButtonCevap4, RadioButton radioButtonCevap5){
this.rootView = rootView;
this.textViewSoruNo = textViewSoruNo;
this.textViewSoru = textViewSoru;
this.radioButtonCevap1 = radioButtonCevap1;
this.radioButtonCevap2 = radioButtonCevap2;
this.radioButtonCevap3 = radioButtonCevap3;
this.radioButtonCevap4 = radioButtonCevap4;
this.radioButtonCevap5 = radioButtonCevap5;
}
public static ViewHolder create(LinearLayout rootView){
TextView textViewSoruNo = (TextView) rootView.findViewById(R.id.textViewSoruNo);
TextView textViewSoru = (TextView) rootView.findViewById(R.id.textViewSoru);
RadioButton radioButtonCevap1 = (RadioButton) rootView.findViewById(R.id.radioCevap1);
RadioButton radioButtonCevap2 = (RadioButton) rootView.findViewById(R.id.radioCevap2);
RadioButton radioButtonCevap3 = (RadioButton) rootView.findViewById(R.id.radioCevap3);
RadioButton radioButtonCevap4 = (RadioButton) rootView.findViewById(R.id.radioCevap4);
RadioButton radioButtonCevap5 = (RadioButton) rootView.findViewById(R.id.radioCevap5);
return new ViewHolder(rootView, textViewSoruNo, textViewSoru, radioButtonCevap1, radioButtonCevap2,
radioButtonCevap3, radioButtonCevap4,radioButtonCevap5);
}
}
}
And my fragment is:
public class FormFragment extends Fragment {
private ListView listView;
private View parentView;
private ArrayList<FormSoru> formSoruList;
private FormSoruAdapter adapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_anket_soru, container, false);
}
#Override
public void onViewCreated(final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
formSoruList = new ArrayList<>();
parentView = view.findViewById(R.id.parentLayout);
listView = (ListView) view.findViewById(R.id.listViewSorular);
APIService apıService = RetroClient.getApiService();
Call<FormSorular> call = apıService.getFormSorular();
call.enqueue(new Callback<FormSorular>() {
#Override
public void onResponse(Call<FormSorular> call, Response<FormSorular> response) {
if (response.isSuccessful()){
formSoruList = response.body().getFormSorular();
adapter = new FormSoruAdapter(getActivity(),formSoruList);
listView.setAdapter(adapter);
}
}
#Override
public void onFailure(Call<FormSorular> call, Throwable t) {
}
});
}
}
My fragment's layout is:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Dear User"
android:layout_margin="10dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Welcome"
android:layout_margin="8dp"/>
<ListView
android:id="#+id/listViewSorular"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Görüşleriniz"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Gönder"/>
</LinearLayout>
And my list_soru layout which contains questions is:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textViewSoruNo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Soru No"
android:layout_margin="10dp"/>
<TextView
android:id="#+id/textViewSoru"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Soru"
android:layout_margin="8dp"/>
<RadioGroup
android:id="#+id/radioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton
android:id="#+id/radioCevap1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="cevap1"/>
<RadioButton
android:id="#+id/radioCevap2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="cevap2"/>
<RadioButton
android:id="#+id/radioCevap3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="cevap3"/>
<RadioButton
android:id="#+id/radioCevap4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="cevap4"/>
<RadioButton
android:id="#+id/radioCevap5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="cevap5"/>
</RadioGroup>
I Found lots of questions for image changing in imageview with another image but I have different problem.
I have to two svg images in xml format in drawable folder.
I want to toggle between images on click of imageview. Like if image a.xml is there then on click on it image b.xml should be displayed, to do that I have to fetch the current xml image source of imageview nd set it to the other one.
How to do that ?
MainActivity.java :
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
ImageView iv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = (ImageView) findViewById(R.id.imageView);
iv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(v == iv){
if(/* How to check current current source of imagevie here */ ){
/* How to set new xml svg source to imagevie here */
}
}
}
});
}
}
xml :
<FrameLayout 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:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
tools:context="com.abcd.MainActivity">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:srcCompat="#android:drawable/alert_dark_frame"
android:src="#drawable/a"
android:layout_centerHorizontal="true"
android:id="#+id/imageView"
android:layout_alignParentTop="true" />
</FrameLayout>
drawable folder containing two svg sources
figured out the partial solution because I can set the new svg source to imageview but still can't the current source :
if(v == iv){
int k = 10;
switch (count) {
case 1 :
iv.setImageResource(R.drawable.a);
k = 0 ;
break;
case 0 :
iv.setImageResource(R.drawable.b);
k=1 ;
break;
}
count = k ;
}
I am running into a strange issue with the RecyclerView loading images dynamically with Glide. Looks like race condition and I looked at this thread but it did not solve the problem:
Recyclerview Adapter and Glide - same image every 4-5 rows
Here's how it looks like screenshot and the red arrows shows the image glitch, notice that the user name text ALWAYS exist.
The code itself looks pretty straight forward:
RV Adapter:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
int viewType = getItemViewType(position);
bindSubscribersCell((SubscribersListViewHolder) viewHolder, position);
}
binding view:
private void bindSubscribersCell(SubscribersListViewHolder holder, int position) {
SubscribersListRowTypeUser subscriberRow = (SubscribersListRowTypeUser) mItems.get(position);
String userFullName = SDKUserHelper.MakeFullName(subscriberRow.getUser());
holder.getUsername().setText(userFullName);
holder.getUsername().setVisibility(View.VISIBLE);
CircleImageView userImageView = holder.getAvatarImage();
Drawable defaultIcon = ContextCompat.getDrawable(
userImageView.getContext(),
R.drawable.avatar_guest);
RecylerViewHelper.loadImageView(
subscriberRow.getUser().getPhotoUrl(),
userImageView,
defaultIcon,
true);
}
the image load helper using the same technique described on the thread I mentioned above:
public static void loadImageView(
String imageUrl,
ImageView imageView,
Drawable drawable,
boolean icon) {
Context context = imageView.getContext();
if (imageUrl != null && !imageUrl.isEmpty()) {
if (icon) {
Glide.with(context).using(CloudinaryHelper.getUrlLoaderPresetPOIIcon(context)).
load(imageUrl).
centerCrop().
crossFade().
into(imageView);
} else {
Glide.with(context).
load(imageUrl).
crossFade().
into(imageView);
}
} else {
Glide.clear(imageView);
imageView.setImageDrawable(drawable);
}
}
the inner layout of the cell:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/user_avatar"
android:layout_width="wrap_content"
android:layout_height="#dimen/splash_icon_height"
android:layout_centerVertical="true"
android:src="#drawable/avatar_guest" />
<TextView
android:id="#+id/user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="40dp"
android:layout_toEndOf="#+id/user_avatar"
android:ellipsize="end"
android:gravity="center"
android:visibility="gone"
android:maxLines="1"
android:text=""
android:textSize="14sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="20dp"
android:src="#drawable/arrow_forward_gray" />
</RelativeLayout>
the wrapper class to fetch the layout controls:
public class SubscribersListViewHolder extends RecyclerView.ViewHolder {
final private CircleImageView mAvatarImage;
final private TextView mUsername;
final private View mViewHolder;
public SubscribersListViewHolder(View itemView) {
super(itemView);
mViewHolder = itemView;
mUsername = (TextView) itemView.findViewById(R.id.user_name);
assert mUsername != null;
mAvatarImage = (CircleImageView) itemView.findViewById(R.id.user_avatar);
assert mAvatarImage != null;
}
public TextView getUsername() { return mUsername; }
public CircleImageView getAvatarImage() { return mAvatarImage; }
public View getViewHolder() { return mViewHolder; }
}
If anyone can spot the race condition, I really appreciate.
thank you!
The fix was to set the icon width and height to a fixed value, so instead of "wrap_content" make some fixed dp (in my case 49dp). In other words:
WRONG (race condition)
android:layout_width="wrap_content"
android:layout_height="#dimen/splash_icon_height"
CORRECT:
android:layout_width="#dimen/splash_icon_height"
android:layout_height="#dimen/splash_icon_height"
But the question now becomes why? I have no idea.
I'm using RecyclerView along with StaggeredGridLayoutManager for showing items with slightly different appearance. in items I use AspectRatioImageView by JakeWharton (link) to maintain the imageView sizes before the image actually downloaded and shown by Picasso. RV (RecyclerView) is populated by server data in infinite scroll pattern.
The problem is (as shown in included pictures), when scolling, some gaps appear on top and bottom of RV (in picture and sometimes items moves between the columns! (taking screenshot is hard :D)
Edit 2: A really important thing I forgot, is that I use the same layout for all of the items but regarding to adapter items some part of the layouts change their visibility to Gone or vice versa.
My question: Why RV behave like this? Am I doing something wrong? Is this normal in RV?
The code is large and I don't know which part is useful to put here. If you can narrow down the cause I will put some code here.
EDIT: Code parts related to problem
xml:
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg_texture"
android:padding="#dimen/padding_lvlhalf"
android:scrollbarStyle="outsideOverlay"/>
initializing view:
#Bind(R.id.recycler_view) RecyclerView mRecyclerView;
.
.
.
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(columnCount, direction));
mRecyclerView.setAdapter(
new RecyclerViewAdapter<>(ctx, new ViewFiller<Post, DashboardPostViewHolder>() {
#Override
public void fill(Post post, DashboardPostViewHolder holder) {
holder.fill(post);
}
#Override
public DashboardPostViewHolder getViewHolder(View view) {
return new DashboardPostViewHolder(view, receiverName);
}
#Override
public int getLayoutID() {
return R.layout.post_dashboard;
}
});)
My custom Adapter:
public RecyclerViewAdapter(Context context, ViewFiller filler) {
super();
this.filler = filler;
mLayoutInflater = LayoutInflater.from(context);
items = new ArrayList<>();
}
#Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View v = mLayoutInflater.inflate(filler.getLayoutID(), parent, false);
return filler.getViewHolder(v);
}
#Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
filler.fill(getItem(position), holder);
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public long getItemId(int position) {
return position;
}
public T getItem(int position){
return items.get(position);
}
public void addItem(int position, T item){
items.add(position, item);
notifyItemInserted(position);
}
public void addItem(T item){
items.add(item);
notifyItemInserted(items.size() - 1);
}
public void addItems(List<T> data){
int oldSize = items.size();
items.addAll(data);
notifyItemRangeInserted(oldSize, data.size());
}
public void addItemsToListHead(List<T> data){
items.addAll(0, data);
notifyItemRangeInserted(0, data.size());
}
public void resetData(List<T> data) {
this.items = data;
notifyDataSetChanged();
}
public void removeItem(int position){
items.remove(position);
notifyItemRemoved(position);
}
public void clear(){
this.items.clear();
notifyDataSetChanged();
}
public List<T> getItems(){
return items;
}
ViewFiller interface
public interface ViewFiller<D, VH extends BaseViewHolder>{
void fill(D data, VH holder);
VH getViewHolder(View view);
#LayoutRes int getLayoutID();
}
Edit 2 (Cont.): My items xml and how I fill them..
<android.support.v7.widget.CardView
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="match_parent"
android:layout_margin="#dimen/margin_lvlhalf"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/post"
android:background="#color/poinila_background">
<TextView
android:layout_gravity="right"
android:text="#string/test_title"
android:layout_margin="#dimen/margin_lvl1"
style="#style/match_wrap.large_text.centered_right"
android:id="#+id/post_title"
android:visibility="gone"/>
<!--Post Image-->
<com.shaya.poinila.android.presentation.view.AspectRatioImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:contentDescription="#string/post_content_description"
android:id="#+id/post_image"
android:visibility="gone"
app:aspectRatioEnabled="true"
app:dominantMeasurement="width"
/>
<!--Content-->
<TextView
android:id="#+id/post_content"
style="#style/match_wrap.medium_text.three_line.end_ellipsize"
android:layout_margin="#dimen/margin_lvl1"/>
<!--android:text="#string/test_long"-->
<include layout="#layout/horizontal_line"
/>
<!--Post Author-->
<include android:id="#+id/post_author"
layout="#layout/circle_image_title_subtitle_reverse"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin_lvl1"/>
<include layout="#layout/horizontal_line"
/>
<!--Post Stats (favs, comments, etc) -->
<include android:id="#+id/post_stats"
layout="#layout/stats"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/margin_lvlhalf"
android:layout_marginBottom="#dimen/margin_lvlhalf"/>
<include layout="#layout/horizontal_line"/>
<!--Post Collection Info-->
<include layout="#layout/rounded_image_title_subtitle_reverse"
android:id="#+id/post_collection"/>
</LinearLayout>
</android.support.v7.widget.CardView>
PostViewHolder class
public class PostViewHolder extends RecyclerView.ViewHolder
public void fill(Post post) {
if (post.type == PostType.IMAGE) {
postImage.setVisibility(View.VISIBLE);
postName.setVisibility(TextUtils.isEmpty(post.name) ? View.VISIBLE : View.GONE);
/*if (TextUtils.isEmpty(post.summary))
postContent.setVisibility(View.GONE);*/
}else{ //post.type == PostType.TEXT
postImage.setVisibility(View.GONE);
postName.setVisibility(View.VISIBLE);
postContent.setVisibility(View.VISIBLE);
}
// contetnt
if (TextUtils.isEmpty(post.summary) && !TextUtils.isEmpty(post.contentUrl)) {
DataRepository.getInstance().getPostContent(post.contentUrl, postContent);
}
else{
setText(postContent, post.summary);
}
.
.
.
}
}
Sorry for the long post!
You probably have margins in your root ViewGroup of item.
manager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
Do this ,spacing between the grid items stay same
private boolean flagDecoration = false;
if(!flagDecoration)
{
ItemOffsetDecoration itemDecoration = new ItemOffsetDecoration(getContext(),(R.dimen.spacing));
recyclerView.addItemDecoration(itemDecoration);
flagDecoration = true;
}