EnhancedListView SwipeRefreshLayout - android

I am using a SwipeRefreshLayout and an EnhancedListView to combine them like GMAIL-App. When I start to swipe horizontal I am still be able to swipe vertical. In this case the animation from EnhancedListView stuck and do not reset or swipe till the end if I do not complete the vertical (SwipeRefreshLayout) swipe.
I can see, that first pull to refresh and then swipeToDismiss does not work. Only first swipe and then refresh. So i guess it is about beeing a parent element.
Possible Solution i thought about:
Check for horizontal scrolling and disable SwipeRefreshLayout with swipeL.setEnabled(false); When finished swipeL.setEnabled(true); But I can not find where to disable and enable it.
My Layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<RelativeLayout
android:id="#+id/footer"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="#0A756E"
android:gravity="center" >
<LinearLayout
android:id="#+id/ll_archiv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/greenbox" >
<TextView
android:id="#+id/tv_archiv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingTop="10dp"
android:text="#string/archiv"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#fff" />
</LinearLayout>
</RelativeLayout>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<de.android.voucheroo.utils.EnhancedListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#id/footer"
android:layout_alignParentTop="true"
android:descendantFocusability="blocksDescendants" >
</de.android.voucheroo.utils.EnhancedListView>
</android.support.v4.widget.SwipeRefreshLayout>
My Code:
swipeL = (SwipeRefreshLayout) getActivity().findViewById(
R.id.swipe_container);
ll_archiv = (LinearLayout) getActivity().findViewById(R.id.ll_archiv);
tv_archiv = (TextView) getActivity().findViewById(R.id.tv_archiv);
elv = (EnhancedListView) getActivity().findViewById(android.R.id.list);
elv.setDismissCallback(new OnDismissCallback() {
#Override
public Undoable onDismiss(EnhancedListView listView,
final int position) {
try {
final Object vouch = voucher.get(position);
voucher.remove(position);
adapter.notifyDataSetChanged();
return new EnhancedListView.Undoable() {
#Override
public void undo() {
voucher.add(position, vouch);
adapter.notifyDataSetChanged();
}
// Return a string for your item
#Override
public String getTitle() {
return "foo";
}
// Delete item completely from your persistent storage
#Override
public void discard() {
[...];
}
};
} catch (Exception e) {
Log.w("ELV_EXCEPTION", e.getMessage());
e.getStackTrace();
return null;
}
}
});
swipeL.setOnRefreshListener(new OnRefreshListener() {
#Override
public void onRefresh() {
[...]
swipeL.setRefreshing(false);
}
});
// Handler
elv.enableSwipeToDismiss();
elv.setSwipingLayout(R.id.ll_parent);
elv.setUndoStyle(UndoStyle.MULTILEVEL_POPUP);

Nowsaday I know the answer of my own question. It is not a problem with my code, it is a problem with SwipeRefreshView.
There is a similar question with the same Problem I found here: SO-Answer

Related

Listview gets cut off when translating by y

Note: These are randomly generated addresses
Hey Guys, Learning Xamarin and I am trying to scroll my Frame Layour down and reveal a search bar for my list view. Here is what is happening:
I color coded my layouts to see if the sizes where a problem, but I dont think they are since my orange layout is plenty big to hold my two entries. Am I using the wrong layouts for this kind of application? I would appreciate any help!
Here is my translation code:
frameLayout.Animate().TranslationYBy(editSearch.Height).SetDuration(500).Start();
And my layout file:
<android.support.v4.widget.SwipeRefreshLayout 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/swipeLayout">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="100dp"
android:id="#+id/frameLayoutParent"
android:background="#android:color/holo_green_dark">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/frameLayout"
android:background="#android:color/holo_green_light">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="300dp"
android:background="#android:color/holo_orange_light">
<Button
android:text="Add New Address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/addNewAddress"
android:maxHeight="20dp" />
</LinearLayout>
<ListView
android:paddingTop="50dp"
android:minWidth="25px"
android:minHeight="300dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/myListView"
android:maxHeight="300dp"/>
</FrameLayout>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/editSearch"
android:hint="Search ZipCodes"
android:textColor="#000"/>
</FrameLayout>
</android.support.v4.widget.SwipeRefreshLayout>
EDIT:
Here is my OnOptionsItemSelected Code, where my animation is triggered.
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Resource.Id.action_search:
//search icon has been clicked
if (isAnimating)
return true;
else
{
if (animateBool)
{
//list view is up
animation anim = new animation(myListView, myListView.Height - editSearch.Height);
anim.Duration = 500;
myListView.StartAnimation(anim);
anim.AnimationStart += Anim_AnimationStartDown; //listener for when animation has started
anim.AnimationEnd += Anim_AnimationEndDown;
classSwipeRefresh.Animate().TranslationYBy(editSearch.Height).SetDuration(500).Start();
}
else
{
animation anim = new animation(myListView, myListView.Height + editSearch.Height);
anim.Duration = 500;
myListView.StartAnimation(anim);
anim.AnimationStart += Anim_AnimationStartUp; //listener for when animation has started
anim.AnimationEnd += Anim_AnimationEndUp;
classSwipeRefresh.Animate().TranslationYBy(-editSearch.Height).SetDuration(500).Start();
}
animateBool = !animateBool;
return true;
}
default:
return base.OnOptionsItemSelected(item);
}
}
Learning Xamarin and I am trying to scroll my Frame Layour down and reveal a search bar for my list view. Here is what is happening:
I use your code to test, but I have no problem when translating by Y in SwipeRefreshLayout__Refresh event.
public class MainActivity : AppCompatActivity
{
string[] items;
ListView listview1;
SwipeRefreshLayout swiplayout;
FrameLayout framelayout;
EditText edittext;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
listview1 = FindViewById<ListView>(Resource.Id.myListView);
swiplayout = FindViewById<SwipeRefreshLayout>(Resource.Id.swipeLayout);
framelayout = FindViewById<FrameLayout>(Resource.Id.frameLayout);
edittext = FindViewById<EditText>(Resource.Id.editSearch);
swiplayout.Refresh += Swiplayout_Refresh;
items = new string[] { "Vegetables", "Fruits", "Flower Buds", "Legumes", "Bulbs", "Tubers" };
listview1.Adapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, items);
}
private void Swiplayout_Refresh(object sender, EventArgs e)
{
framelayout.Animate().TranslationYBy(edittext.Height).SetDuration(500).Start();
}
}
This is my screenshot:
If you want to filter ListView, I suggest you can use SearchView in Toolbar to filter listview data, please take a look this sample:
https://github.com/Cheesebaron/SearchView-Sample/tree/master/SearchViewSample

Horizontal RecyclerView with dynamic item’s Height

I’m trying to implement a RecyclerView with horizontal scrolling, so I’m using this a LinearLayoutManager with horizontal orientation. The problem is that I’m populating the RecyclerView using 2 different types of items, with different heights. This is the layout I’m using for the item:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp">
<LinearLayout
android:id="#+id/document_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#drawable/ic_rounded"
android:backgroundTint="#color/ms_black_ms_gray"
android:gravity="center"
android:layout_gravity="bottom"
android:padding="5dp"
android:paddingStart="15dp">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/white"
android:textSize="13sp"
android:singleLine="true"
android:maxWidth="80dp"
tools:text="example_form"/>
<TextView
android:id="#+id/format"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/white"
android:textSize="13sp" />
…
</LinearLayout>
<android.support.v7.widget.CardView
android:id="#+id/image_view"
android:layout_width="120dp"
android:layout_height="80dp"
android:layout_gravity="bottom"
app:cardCornerRadius="25dp"
app:cardElevation="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/preview_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"/>
…
</RelativeLayout>
</android.support.v7.widget.CardView>
and this is the layout that contains the RecyclerView, which is basically like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="14dp"
android:paddingEnd="14dp">
<ImageView
android:id="#+id/attach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_gravity="bottom"
android:layout_marginBottom="19dp"
android:visibility="visible"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginBottom="10dp"
android:layout_marginTop="5dp"
android:padding="3dp"
android:foreground="#drawable/ic_rounded_stroke"
android:foregroundTint="#color/white">
<android.support.constraint.ConstraintLayout
android:id="#+id/chatEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/ic_rounded"
android:foreground="#drawable/ic_rounded_stroke"
android:padding="6dp"
android:visibility="visible">
<EditText
android:id="#+id/editText"
android:textSize="17sp"
android:textColor="#121212"
android:letterSpacing="-0.02"
android:lineSpacingExtra="0sp"
android:padding="10dp"
android:paddingStart="15dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="5"
android:hint="#string/chat_hint"
android:inputType="textCapSentences|textMultiLine"
android:maxLength="2500"
android:background="#null"
app:layout_constraintRight_toLeftOf="#id/buttonsContainer"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/send"
android:layout_gravity="bottom"
android:visibility="visible"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingBottom="10dp"
android:paddingTop="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#ffffff"
android:letterSpacing="-0.02"
android:gravity="center_horizontal"
android:text="#string/send"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<android.support.v7.widget.RecyclerView
android:id="#+id/filesList"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingTop="5dp"
android:paddingEnd="5dp"
android:visibility="gone"
app:layout_constraintRight_toLeftOf="#id/send"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="#id/editText"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
</LinearLayout>
</LinearLayout>
I’m using a single ViewHolder, I just change the visibility of the 2 child views.
The result I expect to get is this one:
But what I’m getting is this; the CardView being cut in half, using the height of the second type of item:
I saw this post, which is similar to my problem. It recommends using Google’s Flexbox. So, I tried to implement FlexboxLayoutManager:
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(getContext());
layoutManager.setFlexDirection(FlexDirection.ROW);
layoutManager.setFlexWrap(FlexWrap.NOWRAP);
I’m using row direction and It is showing items on next lines if it does not fit in single line. So, I also added No_wrap. And now it is showing items in a single line but do not provide scrolling. Also in this case it tries to fit all items in a single line by decreasing width of items.
I also played with the flex box sample app, but I couldn’t get the result I want.
Is there a way I can achieve horizontal scrolling with the Flexbox integrated with RecyclerView? Or should I use a different approach?
Thanks
EDIT
Thanks for the tips and everything, but it is not solving it. So, I stripped down the code to bare minimum to reproduce this.
MainActivity:
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE = 1;
private RecyclerView recyclerView;
private FilesAdapter filesAdapter;
private List<File> filesList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerView);
LinearLayoutManager filesLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(filesLayoutManager);
filesAdapter = new FilesAdapter(filesList);
recyclerView.setAdapter(filesAdapter);
ImageView attach = findViewById(R.id.attach);
attach.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(Intent.createChooser(intent,"Select Files"), REQUEST_CODE);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
try {
if (data != null) {
List<File> uriList = new ArrayList<>();
if (data.getClipData() != null) { // Multiple files
for (int i = 0; i < data.getClipData().getItemCount(); i++) {
Uri uri = data.getClipData().getItemAt(i).getUri();
Pair<Boolean, File> isValid = isFileValid(uri);
if (isValid.first) {
uriList.add(isValid.second);
}
}
} else { // Single file
Uri uri = data.getData();
Pair<Boolean, File> isValid = isFileValid(uri);
if (isValid.first) {
uriList.add(isValid.second);
}
}
if (uriList.size() > 0) {
for (File file : uriList) {
filesList.add(filesList.size(), file);
filesAdapter.notifyItemInserted(filesList.size());
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private Pair<Boolean, File> isFileValid(Uri uri) throws NullPointerException {
Pair<Boolean, File> defaultResponse = Pair.create(false, null);
Cursor c = getContentResolver().query(uri, null, null, null, null);
if (c != null) {
c.moveToFirst();
String filename = c.getString(c.getColumnIndex(OpenableColumns.DISPLAY_NAME));
if (isSupported(filename)) {
c.close();
return Pair.create(true, new File(StringUtils.endsWithIgnoreCase(filename, ".pdf") ? DOCUMENT : IMAGE));
} else {
Toast.makeText(this, "File format not supported", Toast.LENGTH_SHORT).show();
c.close();
return defaultResponse;
}
}
return defaultResponse;
}
private boolean isSupported(String filename) {
String[] supportedFormats = { ".pdf", ".jpg", ".gif", ".png" };
for (String format : supportedFormats) {
if (StringUtils.endsWithIgnoreCase(filename, format)) {
return true;
}
}
return false;
}
}
Main activity layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:id="#+id/attach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="19dp"
android:padding="10dp"
android:src="#drawable/ic_attach" />
</LinearLayout>
File:
public class File {
public enum Type {
DOCUMENT,
IMAGE
}
private Type type;
public File(Type type) {
this.type = type;
}
public Type getType() {
return type;
}
}
File Adapter:
public class FilesAdapter extends RecyclerView.Adapter<FilesAdapter.BaseViewHolder> {
private List<File> files;
public FilesAdapter(List<File> files) {
this.files = files;
}
#NonNull
#Override
public FilesAdapter.BaseViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(viewType == 0 ? R.layout.document_item : R.layout.image_item, parent, false);
if (viewType == 0) {
return new DocumentViewHolder(view);
} else {
return new ImageViewHolder(view);
}
}
#Override
public void onBindViewHolder(#NonNull FilesAdapter.BaseViewHolder viewHolder, int position) {
viewHolder.bind(files.get(position));
}
#Override
public int getItemViewType(int position) {
if (files.get(position).getType() == File.Type.DOCUMENT) {
return 0;
} else {
return 1;
}
}
#Override
public int getItemCount() {
return files.size();
}
abstract static class BaseViewHolder extends RecyclerView.ViewHolder {
public BaseViewHolder(#NonNull View itemView) {
super(itemView);
}
abstract void bind(File file);
}
static class ImageViewHolder extends BaseViewHolder {
public ImageViewHolder(#NonNull View itemView) {
super(itemView);
}
#Override
void bind(File file) { }
}
static class DocumentViewHolder extends BaseViewHolder {
public DocumentViewHolder(#NonNull View itemView) {
super(itemView);
}
public void bind(File file) { }
}
}
document item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="150dp"
android:layout_height="40dp"
android:background="#drawable/ic_rounded"
android:backgroundTint="#888888"
android:layout_margin="5dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="PDF"
android:textColor="#android:color/white"/>
</LinearLayout>
image item:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="120dp"
android:layout_height="80dp"
android:layout_margin="5dp"
app:cardBackgroundColor="#000000"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="IMAGE"
android:textColor="#android:color/white"/>
</androidx.cardview.widget.CardView>
if I select an image first, and the several pdfs, it works fine:
But if I first select 3 pdfs, and then an image, this happens:
Any idea how to solve this?
I had a similar issue in another project and i solved it by using the Google library FlexboxLayoutManager.
Get the latest FlexboxLayoutManager Library (https://github.com/google/flexbox-layout) and add it into your grandle dependencies (implementation 'com.google.android:flexbox:2.0.1')
In your Activity add the below lines of code: FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(this);
layoutManager.setFlexDirection(FlexDirection.ROW);
layoutManager.setFlexWrap(FlexWrap.NOWRAP);
recyclerView.setLayoutManager(layoutManager);
To make FlexboxLayoutManager work with horizontal scroll add the below code in your adapter (FilesAdapter) in BaseViewHolder class: abstract static class BaseViewHolder extends RecyclerView.ViewHolder {
public BaseViewHolder(#NonNull View itemView) {
super(itemView);
ViewGroup.LayoutParams lp = itemView.getLayoutParams();
if (lp instanceof FlexboxLayoutManager.LayoutParams) {
FlexboxLayoutManager.LayoutParams flexboxLp = (FlexboxLayoutManager.LayoutParams) lp;
flexboxLp.setFlexShrink(0.0f);
flexboxLp.setAlignSelf(AlignItems.FLEX_START); //this will align each itemView on Top or use AlignItems.FLEX_END to align it at Bottom
}
}
abstract void bind(File file);
}
In case it helps anyone else, Kotlin version of MariosP's answer with minor refactors below, but 100% kudos to #MariosP. His answer saved the day for us!
RecyclerView setup (this was from a fragment, called in onViewCreated):
private fun setupRecyclerView() {
val flexBoxLayoutManager = FlexboxLayoutManager(requireContext(), FlexDirection.ROW, FlexWrap.NOWRAP)
with(recycler_view) {
layoutManager = flexBoxLayoutManager
adapter = myAdapter
}
}
Adapter setup:
var items : List<Item>
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bindItem(items[position])
}
In the ViewHolder:
class MyViewHolder(private val itemView: View): RecyclerView.ViewHolder(itemView) {
fun bindItem(item: Item) {
// Do things with item
updateLayoutParamsToAllowHorizontalScrolling()
}
private fun updateLayoutParamsToAllowHorizontalScrolling() {
(itemView.layoutParams as? FlexboxLayoutManager.LayoutParams)?.let {
it.flexShrink = 0.0f
it.alignSelf = AlignItems.FLEX_START
}
}
}
try this for your RecyclerView:
android:layout_height="wrap_content"
Since the XML file that contains your RecyclerView is not complete here I cannot be sure but if your RecyclerView is inside another parent view that is limiting it, then i guess using wrap_content as the height for RecyclerView plus some tweaks should solve it.
Also, note that you are limiting you RecyclerView to the bottom of "editText" from top side so that may be preventing your RecyclerView from expanding too.
All you have to do, is to set recyclerview's height to the height of the biggest item, in your case the image item.
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="wrap_content"
android:layout_height="80dp" />
The reason Image is getting cropped when you choose pdf files first is because the height of recycleView is 40dp which is the height of pdf item. When you try to add a new item without modifying the existing ones, recycleView height remains the same i.e. 40dp. To enforce a minimum height of 80dp (which is the current height of the image layout), we can use minHeight as follows:
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="80dp"
tools:listitem="#layout/document_item"
/>
You can also modify your pdf item layout to align the pdfs center_vertically with image items as follows:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_margin="5dp">
<TextView
android:layout_width="150dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:gravity="center"
android:background="#drawable/ic_round"
android:backgroundTint="#888888"
android:text="PDF"
android:textColor="#android:color/white"/>
</LinearLayout>
Cheers :)
First, I think your main layout is a bit overcomplicated. You could do the whole thing in a single ConstraintLayout (if you need framed background around specific items, I recommend to use pure View instances layed out using Barriers and Guidelines - see https://medium.com/better-programming/essential-components-of-constraintlayout-7f4026a1eb87)
Another addition and/or improvement would be to not use right/left constraints, rather start/end. This prepares your layout for RTL display too.
Also, I highly recommend to use separate layout files and ViewHolders for distinct items in a RecyclerView.
As others pointed out in comments, your RecyclerView is layed out using match_parent which can in turn crop your view. You may want to set this wrap_content.
In the meanwhile, you may also want to update dependencies to use Android Jetpack and ditch support libraries.

ListView not updating after elements added to bound ObservableCollection (Xamarin)

I found many similar questions on StackOverflow, but can't seem to figure out this issue.
I'm trying to bind an ObservableCollection to a ListView so that when the contents of the collection change the ListView will automatically update. Unfortunately, when elements are added to the collection (via button click), the ListView isn't being updated. How can I make the ListView reflect the current contents of the collection?
Note: It seems that if I force layout with listView.RequestLayout(); the listView will contain the correct number of items. However, it won't necessarily contain the right items. For example, if I delete the first item and add a new one at the end, forcing a layout has no effect. If I force the layout after deleting the first item, then again after adding one at the end, the contents are correct.
Activity code
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
ObservableCollection<UserTask> allTasksCollection = new ObservableCollection<UserTask>();
while(count < 6)
{
allTasksCollection.Add(new UserTask("Task number " + count));
count++;
}
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Bind listview to all tasks
ListView listView = FindViewById<ListView>(Resource.Id.allTasksListView);
UserTaskListAdapter adapter = new UserTaskListAdapter(this, allTasksCollection);
listView.Adapter = adapter;
// Button click should add a new task and remove the first task.
Button button = FindViewById<Button>(Resource.Id.myButton);
button.Click += delegate {
allTasksCollection.Add(new UserTask("Task number " + count));
button.Text = string.Format("{0} tasks!", count++);
};
}
}
Adapter
public class UserTaskListAdapter : BaseAdapter<UserTask>
{
Activity context;
ObservableCollection<UserTask> list;
public UserTaskListAdapter(Activity _context, ObservableCollection<UserTask> _list)
: base()
{
this.context = _context;
this.list = _list;
}
public override int Count
{
get { return list.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override UserTask this[int index]
{
get { return list[index]; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView;
if (view == null)
view = context.LayoutInflater.Inflate(Resource.Layout.UserTaskRowItem, parent, false);
UserTask item = this[position];
view.FindViewById<TextView>(Resource.Id.Title).Text = item.Name;
return view;
}
}
Main XAML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/rootLayout">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/allTasksContainer">
<Button
android:id="#+id/myButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/hello" />
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/allTasksListView" />
</LinearLayout>
</LinearLayout>
ListItem XAML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/linearLayoutHorizontal">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/CheckboxContainer">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/checkboxSelect" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/TextContainer">
<TextView
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/Title" />
<TextView
android:text="Small Text"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/DueDate" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Try to call NotifyDataSetChanged() on your adapter after updating its items, AFAIK ListView in Android doesn't observe the changes on your ObservableCollection:
Try this code:
button.Click += delegate {
allTasksCollection.Add(new UserTask("Task number " + count));
button.Text = string.Format("{0} tasks!", count++);
adapter.NotifyDataSetChanged();
};
You can also try to add a litener to your ObservableCollection, in your adapter, change the constructor to this:
this.list.CollectionChanged += (sender,args) => { NotifyDataSetChanged(); };
Take a look at the INotifyPropertyChanged interface. It will warn the listview that variables within an object within the listview have changed.
https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/
Edit: misread your question. My bad.

RecycleView inside NestedScrollView with match_parent

I have a layout with custom ScrollView that can be switched off. There are some fragments loading into this ScrollView.
Today I added RecycleView to the new fragment and noticed a strange behaviour. When RecycleView has android:height="match_parent" it expands to full its height inside ScrollView.
Is there any way to disable this (I want RecycleView to scroll internally and to be screen_height size) ?
Main content xml (located inside CoordinatorLayout)
<xxx.SwitchableScrollView
android:id="#+id/main_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:id="#+id/fragment_holder"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="ScrollViewSize"/>
</xxx.SwitchableScrollView>
Fragment layout:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/appeals_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="visible"/>
<LinearLayout
android:id="#+id/loading_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar
android:layout_width="#dimen/big_progress_diameter"
android:layout_height="#dimen/big_progress_diameter"
android:indeterminate="true"
android:indeterminateDrawable="#drawable/custom_progress_bar_primary"/>
</LinearLayout>
</FrameLayout>
Extended ScrollView:
public class SwitchableScrollView extends ScrollView {
boolean allowScroll = true;
public boolean isAllowScroll() {
return allowScroll;
}
public void setAllowScroll(boolean allowScroll) {
this.allowScroll = allowScroll;
}
// .... constructors skipped
#Override
public boolean onTouchEvent(MotionEvent ev) {
return allowScroll && super.onTouchEvent(ev);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return allowScroll && super.onInterceptTouchEvent(ev);
}
}
RecycleView init:
listView = (NestedRecyclerView) v.findViewById(R.id.appeals_list);
listView.setHorizontalScrollBarEnabled(false);
listView.setVerticalScrollBarEnabled(true);
listView.setNestedScrollingEnabled(true);
adapter = new AppealListAdapter(appealList);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
listView.setLayoutManager(layoutManager);
listView.setAdapter(adapter);
new GetAppeals().execute();
I'm using support library 23.2.1 (also tried 23.2.0). ListView and GridView works good in another fragments.
Finally I found an answer. I spent 6 hours(!) to add this one line to code:
layoutManager.setAutoMeasureEnabled(false);
They should be crazy to enable such thing by default...

Create a panel that slides up and out of the screen in Android

i need some guidance. I need to make a custom view that touched and drag up the screen slides out of the screen. I have tried this cool library: here but this is dependend to exactly 2 layouts. The one that is slided out and the one that remains after that. What i have now is buggy and ugly.
public class DemoActivity extends Activity {
private SlidingUpPanelLayout mLayout;
private RelativeLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
layout = (RelativeLayout) findViewById(R.id.panel);
final int defaulttop = layout.getTop();
final int defaultbottom = layout.getBottom();
RelativeLayout dragView = (RelativeLayout) findViewById(R.id.dragView);
mLayout = (SlidingUpPanelLayout) findViewById(R.id.sliding_layout);
mLayout.setDragView(dragView);
mLayout.setPanelSlideListener(new PanelSlideListener() {
#Override
public void onPanelSlide(View panel, float slideOffset) {
}
#Override
public void onPanelExpanded(View panel) {
System.out.println("panel expanded");
}
#Override
public void onPanelCollapsed(View panel) {
System.out.println("panel collapsed");
}
#Override
public void onPanelAnchored(View panel) {
System.out.println("anchored");
}
#Override
public void onPanelHidden(View panel) {
System.out.println("panel is hidden now");
}
});
}
#Override
public void onBackPressed() {
if (mLayout != null && mLayout.isPanelExpanded()) {
mLayout.collapsePanel();
} else {
super.onBackPressed();
}
}
}
The layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DemoActivity" >
<com.sothree.slidinguppanel.SlidingUpPanelLayout
xmlns:sothree="http://schemas.android.com/apk/res-auto"
android:id="#+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"
android:gravity="bottom"
sothree:dragView="#+id/dragView"
sothree:panelHeight="60dp"
sothree:paralaxOffset="60dp"
sothree:shadowHeight="0dp" >
<RelativeLayout
android:id="#+id/panel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/unt"
android:orientation="vertical" >
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:text="Sleep" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/dragView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"
android:clickable="true"
android:focusable="false" >
</RelativeLayout>
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
</RelativeLayout>
it slides up but leaves a white background in the back. If i touch the screen then it slides. So, i need a new path. Did anyone confrunted with something similar? I need a hint, not code. Thanks.
I have used the library you mentioned here and it worked out fine for me. You might have not set the drag view/layout
Do use mSlidingPanelLayout.setDragView(YourLayout) to set the layout that can be dragged
I have done something like this previously but with a button.
I did it using Animation class when moving it by OnTouchListener. While you have to be careful while using it and control the X and Y values of the layout.

Categories

Resources