I have a working example of a grid that allows items to be reordered using long touches to active a drag-n-drop. All is working well if the items are simple Views e.g. TextView or ImageView but if the items are LinearLayouts only the layout itself is displayed.
I've been using Tom Quinsn's grid (thanks Tom!!!) from this posting:
Android Gridview drag and drop example
I can get LinearLayouts to work if I derive my own LinearLayout class and override onLayout(), but this forces me to hardcode the positions of the child controls in the layout within this function.
Ideally I would like to be able to define the item layout within an XML file and inflate them before adding them to the Control that handles the grid. I'm guessing that for some reason the framework is not calling the layout function for the children contained within the DraggableGridView view as defined in Tom's code but I can't understand why that is.
I am developing my own Drag and Drop app with good help from this link. You may compare the code with the one from Tom Quesinsn. It also gets the different children of a GridView and add them as "drop targets" that accepts drops on them and copy the Image of the View you are dragging.
This is a known problem with the DraggableGridView that -- unfortunately -- I haven't gotten around to fixing. When I wrote DGV, I didn't entirely grasp how views were laid out. You might try having DGV measure each child before laying it out. Adding something like:
getChildAt(i).measure(MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY));
before the layout on this line:
getChildAt(i).layout(xy.x, xy.y, xy.x + childSize, xy.y + childSize);
Related
I would like to create a grid layout in which each item is taking as much space as possible (minus padding), but only as long as there are columns available (after that the next item would be inserted in the next row while keeping the size). Additionally, each item must be a square and is added dynamically.
Example layout with 10 items would be as follows:
I have tried to achieve this by setting weights, ratio constraints, overriding onMeasure - but I just can't get it to work. I would be happy with either a programmatic or an XML-based solution (as long as each item can be added programmatically). I would prefer the solution to be in Kotlin, but I would be happy with a Java-based one as well.
It's probably worth saying that each item in the grid layout is a layout (RelativeLayout as of now) to make inflating it and setting a layered background drawable programmatically easy.
I think you might be able achieve what you want with a different Layout
Have a look at https://github.com/google/flexbox-layout it has lots of methods to control how the cells grown or shrink and includes automatic or manual wrapping of cells.
Take a look at RecyclerView. You would need to pass GridLayoutManager. This tutorial may or may not help you. For square items, I suggest using CardView but it's not necessary. If you are targeting tablets as well as smartphones, check this out. And for dynamically adding new items, you should notify recyclerView's adapter. See this link. You can also extend RecyclerView or GridLayoutManager for more control over items.
Everyone knows that GridView does not supports headers and footers like a ListView.
There is a few ways to implementing this:
Use a ListView and form columnt manually via ViewGroups. It not works for me, because it's require a lot of layout operations like measuring and layouting, and it's difficult to implement draw selector on top.
Use special adapter. It works fine with a footer: we should fill last cells with a Space and manually insert after them out footer with width that equals GridView width. But this not works with headers: although header is stretched, next cells float on it.
Use a GridLayout. GridLayout is good, but what about performance with 500-1000 cells? AdapterView supports caching and reusing Views, as far as I know, this is not possible with GridLayout.
Extend GridView and write custom class, that allows to draw a header before the grid content. It's difficult, but it's should work very fast. Let's try to figure out how to do this:
Measure the header. It's very simple, I have not questions about this.
Layout header in the top of the grid. We also should consider with scrolling position to allow move header with whole grid content, so my first question is: how to know where bottom border should be located while scrolling?
Layout whole grid content after the header. How to do that? I've newer do this before.
Dispatch draw to the header view too and resolve overscrolling effect if it's not work well.
Handle the scroll event and refresh header position.
So what you can suggest me? How to do header offset? Is it right to invoke relayouting with every scroll event?
I searched an answer on a same situation with a GridView (but for a FooterView).
I've read attentively your suggestions and some from other websites. I had the same reflexion. I found a simple way as your tip: "Use special adapter. It works fine with a footer..." and this answer by #RaulSoto helped me a lot. But when I tried to update my gridview, I had a NPE, because my footer was not like the layout of my items and I had a custom filter which recalculated the getCount() method, but without understand that another view was added.
Finally, I found only solution which works: a custom class.
Create your own class as you said: "Extend GridView and write custom class" but don't extend GridView. You should extend with ListView and measure the entire width, the column width and the number of columns. I think, it's less difficult that to extend GridView, calculate the height of the header view and move it as you move your gridview or refresh the header each time you handle a scroll event..
I searched to do it in this way and I took this little project on GitHub: HFGridView by Sergey Burish. It was exactly what I need, no more.
I only added a custom attrs file in my app and customize a bit his project to have the expected result (especially, it was to have one column in portrait, two in landscape mode, refering to the numColumns attribute in my layout).
And when I try, just for test, to add a HeaderView and refresh the content with adding new items, the header view stays at the top of my gridview list, without refreshing himself.
So, I think you should search to create your class as GridView extends ListView. Refer you to the HFGridView by SBurish, it is very simple to understand how it does.
Hope this helps you with your purpose.
I have a ListView with a HeaderView.
I want one of the views in the HeaderView to stick on top.
I've seen a lot of examples for sticky Section Headers.
I also looked at StickyScrollViewItems but since I'm using a ListView, I cannot use a ScrollView.
Is there a library available for this or should I just override the OnScrollListener of the ListView?
Thanks.
I have just written a load of code that does this that I cant share for contractoral reasons. Basically follow the approach outlined here and apply to a listview rather than a scroll view.
Main points are
Create a wrapper view that contains your floating/sticky header and your listview as siblings
Use a proxy method when adding headers with an isSticky boolean - if is sticky then add a fake blank header to the listview of the same size and your intended header view to the floating header wrapper (use a relative layout here)
Set a scroll listener of the listview that tracks the top px position of the dummy header view in the list and setting this as a top margin of the floating header that sits inside a relative layout
Handle all the annoying edge cases / OEM overscroll crap to get it to work in all situtions (like this for samsung)
Remember to set the initial position of the floating/pinned header after the listview has been layed out.
I feel its a little bit involved and takes some tweaking to get right - this is a time where i envy iOS and any iOS devs will think your slacking as it takes a while to implement :D
All the Open libs out there at time of writing are using scroll views or list view headers. This issue with these approaches are that list views recycle views (so unlike scroll views you cant just keep a ref to the dummy view) and also the current libs seem duplicate the sticky views using adapter getView methods and so on - which is no good for dynamic list view header views as they are not recycled and can only have one parent, so reparenting would be annoying (and in my case has a lot of functionality so I defo dont want to create two views of the same type and shoehorn the current libs to fit my solutions)
I don't know of any library that lets you do this but what I do for a header is to use a RelativeLayout for my xml that will have the ListView. Then create your header view however you want and give it the property
android:layout_alignParentTop="true"
then give your ListView
android:layout_below="#id/idOfHeaderView
This is the easiest way I know of to dock a header view at the top. It has worked for me every time. I hope this helps.
I am going to start one app where my activity page will contain "n" grouped views. Grouped view means "collections of views (i.e. One group can have TextView+Button+ImageView)". So the page will have "n" number of such grouped views.
I need suggestions like what would be the best practice to implement this. I could think of below ones:
1) Should a ScrollView be used (Then I will have to create groups in runtime and place one under another)?
2) Or a ListView be used (Then how can I accommodate the height of each row as grouped views height may differ from each other?)
Or is there any other way I can go along with?
Appreciate the suggestions and any sample examples if have. Advance Thanks.
Both options would work, it really depends on your use case.
Place a vertical LinearLayout inside of a ScrollView and add your grouped-views to the LinearLayout. I would recommend this if you have a relatively small number of such views (not necessarily a fixed number, but small enough that you wouldn't have to scroll many "pages" to see them all). Make sure the ScrollView has android:layout_height="match_parent" and the LinearLayout has android:layout_height="wrap_content".
If the number of grouped-views is not small, you could use a ListView and make an Adapter for it. This lets you take advantage of ListView's automatic view recycling when items get scrolled off screen.
For either case, make an XML file for just the grouped-views. In code, you would get a LayoutInflater object (usually by calling Activity.getLayoutInflater()) and call inflate(R.layout.your_grouped_views, null). If using the LinearLayout, you would add it in code with one of the LinearLayout.addView(..) methods; if using the ListView, your adapter would return the whole thing from getView(...).
create one xml layout containing the constant elements of your group view.
in you main xml layout which will be the contentView of your application, put a ScrollView and a single LinearLayout.
then in the program inflate as many views of your group view as you want.
For your answer i want to give you referance of this website, on this website you can learn create dynamic view in android...
I'm actually making an application using a ViewFlipper to display 3 differents custom views. These views are, for each one, in a ScrollView (putting the ViewFlipper in a single ScrollView isn't making my onFling gestures really efficient). And i'm actually trying to synchronize the three Scrollbars position. At this point using a single ScrollView would have been easier but i trying to not use this solution.
I'm using a ScrollListener for each ScrollView to set the others ScrollView scroll position like in this thread : Synchronise ScrollView scroll positions - android.
The problem is that this method will works but the first time. When i'm on a ScrollView, the two others are not drawn already and their height is null. So setting their scroll position isn't working.
/*Instanciate ScollViews*/
scrollViewLeft = (ScrollableScrollView) findViewById(R.id.scroll_prev);
scrollViewCenter =(ScrollableScrollView) findViewById(R.id.scroll_current);
scrollViewRight = (ScrollableScrollView) findViewById(R.id.scroll_next);
/*Fill views with events*/
setDayEvents(calIns.getPrevCal(),leftDayView);
setDayEvents(calIns.getActualCal(),centerDayView);
setDayEvents(calIns.getNextCal(),rightDayView);
scrollViewLeft.setScrollViewListener(this);
scrollViewCenter.setScrollViewListener(this);
scrollViewRight.setScrollViewListener(this);
So finally my question is, should i use another method to find the scroll position of the two others views ? Or can i force the view to be drawn in a ViewFlipper ?
Thanks :)
Clement.
Try saving the positions in global variables before you change the views and then just apply it to your current view.
Thanks Egor for having answered. I think it is a good idea. I already have a Singleton to handle variables. So i add the variable position with getters and setters.
The probleme here is than even if I override the method "onSizeChanged" in my custom ScrollView, this will apply only for the first view shown.
PS: I'm still starting on Android development and I don't really know how to handle with
interactions on views when they aren't ready (for example getting width when they are not drawn yet).
Edit 1 day later :
Ok i found what was the problem, it is because the size of my views inside the scrollviews wasn't defined (the scrollview was drawn before the view inside it). So by setting the scroll inside the "onSizeChanged" method of the views works well.