Hello Can i make like this image with recycle-view layout manger?
and this image show what i want to do thank in advance.
Use ReycyleView using GridLayoutManager
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
if (position == 0) {
return 2; // Splitting into 2 columns
} else {
return 3; // Splitting into 3 columns
}
}
});
Yes u can ...in recycler_adapter check if position == 0 then make the two cardsview visible and set them... and in else {cardview4 ,cardview5,cardview6 visible and set them and make cardview1 and cardview2 Gone the inflate layout will contain a relative lat
yout with two horizontal linearlayouts just hide make the layouts gone and visible at proper position in onBind()
for achieving this view i think GridLayoutManager with it's setSpanSizeLookup() method is the best choice. you can find complete explanation in this answer. In case you face any problem while implementing you can ask.
Related
I need some help with my GridLayoutManager.
If I have an item it should be displayed as normal in the middle.
For two items these should be next to one another.
Example with 2 Items
From three to four items it should be displayed like a square.
Example with 3 Items
Example with 4 Items
If I'm right, this should be the case with spanCount 2. But that with the 5 items (so three in a row) is then problematic
From five items (and up) should each be 3 in a row
Example with 5 Items
It would be especially good if the items in the bottom row were also in the middle
I hope someone can help me and thanks in advance
You can set your span dynamically by subclassing GridLayoutManager like this :
class CustomGridLayoutManager(context: Context) : GridLayoutManager(context, 2) {
override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
updateSpanCount()
super.onLayoutChildren(recycler, state)
}
private fun updateSpanCount() {
val colCount = if (childCount <= 4) {
2
} else {
3
}
this.spanCount = colCount
}
}
If you want to center your elements in the last row, it would a little convoluted to do it through GridLayoutManager. You might want to check FlexboxLayout for that purpose. It's a library made by Google itself and has flex box model found commonly in HTML5 / CSS world.
I want to Highlight a single row of recyclerview with sound one after another and scroll the highlight row to top of screen This is what i have done:
Here its code:
fun AnimateToSurahAlFeel(recyclerView: RecyclerView, layoutManager: LinearLayoutManager, currentPosition: Int) {
var position: Int = currentPosition / 1000
when (position) {
0 -> {
recyclerView.smoothScrollToPosition(0)
recyclerView.getChildAt(0).isSelected = true
}
4 -> {
recyclerView.smoothScrollToPosition(1)
recyclerView.getChildAt(0).isSelected = false
recyclerView.getChildAt(1).isSelected = true
}
11 -> {
recyclerView.smoothScrollToPosition(2)
recyclerView.getChildAt(1).isSelected = false
recyclerView.getChildAt(2).isSelected = true
}
17 -> {
recyclerView.smoothScrollToPosition(3)
recyclerView.getChildAt(2).isSelected = false
recyclerView.getChildAt(3).isSelected = true
}
21 -> {
recyclerView.smoothScrollToPosition(4)
recyclerView.getChildAt(3).isSelected = false
recyclerView.getChildAt(4).isSelected = true
}
28 -> {
recyclerView.smoothScrollToPosition(5)
recyclerView.getChildAt(4).isSelected = false
if (recyclerView.getChildAt(5) != null)
recyclerView.getChildAt(5).isSelected = true
}
}
}
In the Function currentPosition is Media player current position
Problem in this code is:
In the Screen shot Row 4 and 5 are currently not visible,when highlighting Row 4 and 5 the App crash and giving Null Pointer Exception, according to my knowledge these two row are not yet created that's why
recyclerview.getChildAt(4) or recyclerview.getChildAt(5) return null and that cause the App crash.
Now
How to fix the App crash that recyclerview.getchildAt(4) or recyclerview.getchildAt(5) return null and also getChildAt(position) return n-1 row, so the App crash at recyclerview.getchildAt(5) will occur anyhow but i want n Row because i want to highlight all rows
How to scroll the highlighted row to position 0 (at top)
i.e. Row 0 go up from screen and Row 1 take it position and so on...
I want to achieve like this the highlighted one is at top and that will go off from screen when another row is highlighted
You need time for View to Bind. Just for ex. you can post action.
....
17 -> {
recyclerView.smoothScrollToPosition(3)
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
recyclerView.getChildAt(2).isSelected = false
recyclerView.getChildAt(3).isSelected = true
}, 500);
}
....
But I strongly recommend you use some state Collection, which will save and handle states of your running and showing Views.
This is because recycler views don't have all the views inflated, but only the visible ones. This is by design and should not be tinkered with. Personally, I think you should use the recycling functionality.
You need to make the selected state part of your model in the adapter - the items in the adapter. Let's say this is called RowItem, so in your adapter you'd have a list of RowItems for example. Aside from the text in both languages, you need to add the selected state too. Then it's just a matter of getting the list's adapter, setting the correct position to selected and deselecting the ones you want.
For example, in your adapter:
fun select(position: Int) {
data[position].selected = true
notifyItemChanged(position)
// deselect all other positions that you don't want selected
}
When you bind the view holder you could do then:
public void onBindViewHolder(ViewHolder viewHolder, int position) {
val item = data[position]
viewHolder.itemView.selected = item.selected
// take care of the rest of the views
}
data would be a list where you store your RowItems
Now you can scroll with no problem and set the item to selected. Once the view is visible in the recycler view, the adapter will set the correct state.
It's fair to say I'm guessing a bit since there's no adapter code in your question, but the idea I think it's easy to understand. You need to change the state in the adapter and let the implementation of the recycler view handle it for you. After all the purpose is to get the recycler view to recycle your views based on the models adapted by the adapter.
Remember you can always get your adapter from the recycler view itself. In the end you can do something like this:
...
0 -> {
recyclerView.smoothScrollToPosition(0)
(recyclerView.adapter as MyAdapter).select(0)
}
Here MyAdapter would be the class name of your adapter
For the scrolling part you can take a look at this
I'm trying to read if there is any image or not, then if image is null, I make the imageview in post card gone. If not then load it using Glide.
It works when I load the recyclerview for first time. But after some scrolls, those imageviews get invisible(View.gone)
onBindViewHolder:
DataSnapshot d = topics.get(position);
holder.text.setText(d.child("caption").getValue(String.class));
if (d.child("type").getValue(String.class)!=null&&d.child("type").getValue(String.class).equals("image")){
Glide.with(c).load(d.child("image").getValue(String.class)).placeholder(R.drawable.background).centerCrop().into(holder.image);
}
else{
holder.image.setVisibility(View.GONE);
}
holder.name.setText(d.child("username").getValue(String.class));
holder.category.setText(d.child("category").getValue(String.class));
long millis = System.currentTimeMillis();
long posttime = d.child("time").getValue(Long.class);
long timedifference = millis-posttime;
int days = (int) (timedifference / (1000*60*60*24));
if (days<2){
holder.time.setText("Today");
}else {
holder.time.setText(days+" days ago");
}
if (d.child("pic").exists()){
Glide.with(c).load(d.child("pic").getValue(String.class)).placeholder(R.drawable.background).centerCrop().into(holder.pic);
}
So where am I doing wrong?
It is better to set the visibility first in your case as you are passing the image view to Glide to setup.
We never know what will happen with the glide library update, in case it library wants to access the dimensions. Especially you are making it GONE in else part, which is a bit different from making INVISIBLE.
if (d.child("type").getValue(String.class)!=null&&d.child("type").getValue(String.class).equals("image")){
holder.image.setVisibility(View.VISIBLE);
Glide.with(c).load(d.child("image").getValue(String.class)).placeholder(R.drawable.background).centerCrop().into(holder.image);
}
else{
holder.image.setVisibility(View.GONE);
}
Try this code snippet :
if (d.child("type").getValue(String.class)!=null&&d.child("type").getValue(String.class).equals("image")){
Glide.with(c).load(d.child("image").getValue(String.class)).placeholder(R.drawable.background).centerCrop().into(holder.image);
holder.image.setVisibility(View.VISIBLE);
}
else{
holder.image.setVisibility(View.GONE);
}
When you are setting visibility gone it won't be visible by it self.
you need to visible it when glide load the image and gone when image
is null.
Add holder.image.setVisibility(View.VISIBLE); in if condition.
RecyclerView creates new views first time for first visible data objects and when you scroll to load other items it reuses those views which has been scrolled to top and reuses those views again for new data items.
So whatever the visibility status of that view was when it was created for the first time, it will get retain and will be used for the other items as well.
What you need to do is to set the view VISIBLE explicitly to show it again:
if (d.child("type").getValue(String.class)!=null&&d.child("type").getValue(String.class).equals("image")){
holder.image.setVisibility(View.VISIBLE)
Glide.with(c).load(d.child("image").getValue(String.class)).placeholder(R.drawable.background).centerCrop().into(holder.image);
}
else{
holder.image.setVisibility(View.GONE);
}
I have a linear layout that I am adding several views to. Think linear layout of result items. It is possible for there to be up to 150 result items. Generating each view takes a bit, so I want them to show up as they become available.
Here is my current code:
for (final Dealership loc: locations) {
final int x = resultNumber;
view.post(new Runnable(){
public void run(){
if(loc != null && parent != null && currentLocation != null) {
View v = getResultView(x, loc, parent, currentLocation);
v.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
if(parentLayout != null) {
parentLayout.addView(v);
}
}
}
});
resultNumber++;
}
This works in that it runs in the background and adds all the items. The only problem is that all the views appear at once, after a few seconds. I would really like it if they appeared as soon as they were created.
Is there a way I can modify this code so that it works as desired? Am I going about this the wrong way?
Thanks!
It seems like instead of a LinearLayout, you'll want to instead go with a ListView.
A ListView would give you a scrolling list of elements that are backed by a Collection of some sort (Array, List, etc.), and you could update that list on the fly. This is helpful for when you are slowly aggregating data from an external resource.
ListView also does some optimizing under-the-hood, and will only render row views when they are shown on the screen. If it is taking some time to render all 150 views in your LinearLayout, a ListView would help you here as well.
I'm looking for a solution since too long now and I feel stuck. So I decided to write my first post on stackoverflow :)
I'm trying to do a CoverFlow for my app in android 4.0 and higher, after some research I decided to do that with a ViewPager, to increase the OffscreenPageLimit, and to put a negative margin and in bonus a little PageTransformer for the effect.
So my bug is about the z-index when the margin is too negative one image overlay an other, because of the drawing order, the image on the left is on the top and it's not pretty at all.
See bug here --> http://img33.imageshack.us/img33/2448/r1l1.jpg
So after some research the solution appear to be to overwrite the getChildDrawingOrder method in my ViewPager class. I did it like that :
private void setChildDrawingOrder() {
int count = getChildCount();
positions = new SparseIntArray(count);
for (int i=0, j=0 ; i<count ; i++) {
if (i == position) {
positions.put(count-1, i);
} else {
j++;
positions.put(count-1-j, i);
}
}
mNeedsToSetChildDrawingOrder = false;
}
#Override
protected int getChildDrawingOrder(int childCount, int i) {
if(i == 0 && mNeedsToSetChildDrawingOrder) setChildDrawingOrder();
return positions.get(i);
}
Where positions is an SparseIntArray, where the item on the top got the higher value (childCount-1). I fill it in the onPageSelected (method implement with OnPageChangeListener on my ViewPager) to get the position of the item that i want it to be on the top.
#Override
public void onPageSelected(int position) {
if (lastPosition != position) {
lastPosition = position;
ViewPager viewPager = ((MainActivity)mAdapterContext).getViewPager();
viewPager.setPosition(position);
}
}
I can't see where is my mistake! I also tried something with bringChildToFront in the onPageSelected without any success, probably because the PageTransformer redraw everything after the onPageSelected is called.
Any idea ?
Thanks
EDIT 15/10/13 :
I edit my code because I didn't catch what the method do very weel! It's "to get the index of the child to draw for that iteration." and not "when should I draw child i?" (thx to this post)
I also had some NullPointerException` because the count where not everytime the same so I move it into my ViewPager.
It's way better but still have some drawing bug! My positions SparseIntArray look good so I don't understand. It seems to appear kind of randomly...