I'm using the twoway view for the first and i'm struggling to specify the layout attributes for the views. I have tow kinds of views, header and the episode.
This is the xml of both:
Show:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_margin="#dimen/margin_16dp"
android:layout_width="248dp"
android:layout_height="160dp"
android:background="#color/black">
//More views...
</RelativeLayout>
Header:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="54dp"
android:background="#color/red_800">
//More views
I set the height to be 54dp in the header and 160dp for the show but what i'm getting is this, it's always the same (wrong) height, the red bar is the header.
http://postimg.org/image/xx1dk45n9/
Code:
public static class ViewHolder extends RecyclerView.ViewHolder{
public TextView title,date,rate,episode;
public ImageView image;
public ViewHolder(View view) {
super(view);
image = (ImageView)view.findViewById(R.id.image);
title = (TextView)view.findViewById(R.id.title);
date = (TextView)view.findViewById(R.id.date);
rate = (TextView)view.findViewById(R.id.rate);
episode = (TextView)view.findViewById(R.id.episode);
}
}
public static class ViewHolderHeader extends RecyclerView.ViewHolder{
public TextView date,children;
public ViewHolderHeader(View view) {
super(view);
date = (TextView)view.findViewById(R.id.date);
children = (TextView)view.findViewById(R.id.children);
}
}
public CalendarAdapter(Context context) {
mContext = context;
readDateFormat(context);
simpleDateFormat = new SimpleDateFormat(datePattern, Locale.US);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view;
if (viewType == CalendarGridItem.TYPE.SHOW.ordinal()){
view = LayoutInflater.from(mContext).inflate(R.layout.calendar_grid_tile, parent, false);
return new ViewHolder(view);
}
else {
view = LayoutInflater.from(mContext).inflate(R.layout.calendar_grid_header, parent, false);
return new ViewHolderHeader(view);
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final View view = holder.itemView;
final CalendarGridItem item = mShows.get(position);
final SpannableGridLayoutManager.LayoutParams lp =
(SpannableGridLayoutManager.LayoutParams) view.getLayoutParams();
if (getItemViewType(position) == CalendarGridItem.TYPE.HEADER.ordinal()){ //Header
final ViewHolderHeader holder1 = (ViewHolderHeader)holder;
CalendarHeader header = (CalendarHeader)item;
Log.d(TAG,"Entrou header: "+header.getDate());
//Mete a colSpan a 2
if (lp.colSpan != 2)
lp.colSpan = 2;
lp.height = 100; //Even forcing the height doesn't work
view.setLayoutParams(lp);
}else{ //Show
final ViewHolder holder1 = (ViewHolder)holder;
UpcomingShow show = (UpcomingShow)item;
if (lp.colSpan != 1)
lp.colSpan = 1;
view.setLayoutParams(lp);
}
}
Fragment layout:
<org.lucasr.twowayview.widget.TwoWayView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/spanGrid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background"
style="#style/TwoWayView"
app:twowayview_layoutManager="SpannableGridLayoutManager"
app:twowayview_numColumns="2"/>
What i'm doing wrong ? I'm not used to the recycler view way of doing things, i must be missing something. Teste with Android 4.1.1 and 4.4
Currently have quite the same problem (mine is that elements are all "squares")
It seems like it not possible to give specific height/width for elements in the item layout.
When you look in the source code, in the SpannableGridLayoutManager.java file, you have the method : LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp).
In there, those are the incrimated lines :
final LayoutParams spannableLp = new LayoutParams((MarginLayoutParams) lp);
spannableLp.width = LayoutParams.MATCH_PARENT;
spannableLp.height = LayoutParams.MATCH_PARENT;
But if you do remove that, you "break" all the logic for the spannable grid view...
I also thought that TwoWayView can display the items as squares. So I was digging in the source and found , like Wicha said, that MATCH_PARENT in two places was causing the undesired behaviour.
So I made the following adjustments in the SpannableGridLayoutManager file (commented some lines in checkLayoutParams method) :
#Override
public boolean checkLayoutParams(RecyclerView.LayoutParams lp) {
// if (lp.width != LayoutParams.MATCH_PARENT ||
// lp.height != LayoutParams.MATCH_PARENT) {
// return false;
// }
if (lp instanceof LayoutParams) {
(.....)
}
and here (use width and height from layout params in generateLayoutParams method) :
#Override
public LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
final LayoutParams spannableLp = new LayoutParams((MarginLayoutParams) lp);
spannableLp.width = lp.width; //LayoutParams.MATCH_PARENT;
spannableLp.height = lp.height; //LayoutParams.MATCH_PARENT;
if (lp instanceof LayoutParams) {
(....)
}
Also, in your Adapter class, goes something like this :
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int i) {
viewHolder.image.setScaleType(ImageView.ScaleType.FIT_XY);
viewHolder.image.setPadding(5,5,5,5);
SpannableGridLayoutManager.LayoutParams layoutParams = ((SpannableGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams());
layoutParams.width = cell_width * item.size; //multiply size
layoutParams.height = cell_height * item.size;//multiply size
layoutParams.colSpan = item.size;
layoutParams.rowSpan = item.size;
viewHolder.image.setLayoutParams(layoutParams);
}
Some observations:
cell_width is calculated like screen width/3 in portrait orientation and screen width/4 in landscape.
cell_height is calculated like image_width / image_ratio.
item.size : I decided to have 1:1 or 2:2 or 3:3 aspect ratios for the items, so item_size is the multiplication value.
Related
I want to dynamically create rectangle shape by using float values from server. The shapes should be precise like if any value is 25.2 and another is 25.3 then the 25.3 one should look bigger like we see in charts. So is there any way to achieve this? Here's the image:
I was trying to change the view size by using this:
itemView.tv_value.layoutParams = LinearLayout.LayoutParams(width,height)
But this seems to be accepting integer values only and if float converted to int using double then it will round off to the nearest number and it won't work.
How to achieve this either by using canvas or views?
First of all width or height of any view can not be float value.
You can set int value based on pixel of screen and float value ratio.
Layout for adapter to generate graph...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="50dp"
android:layout_marginLeft="5dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_weight="0.8"
android:layout_height="wrap_content"
android:minHeight="50dp"
android:orientation="vertical"
android:gravity="center_vertical|center_horizontal|left"
android:id="#+id/lo_dynamic_view_container">
</LinearLayout>
<TextView
android:id="#+id/tv_chart_value"
android:layout_width="0dp"
android:layout_weight="0.2"
android:minHeight="50dp"
android:textColor="#000"
android:gravity="center_horizontal|center_vertical"
android:layout_height="match_parent"/>
</LinearLayout>
Generate Ration
private float getRatio(int width, float value, float highestValue){
float result = 0;
result = ( (float)width/highestValue) * value;
Log.e("Result", "width: "+ width +" "+(int) Math.floor(result)+"");
return result;
}
Combine Activity and adapter calss
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
ArrayList<Data> listData = new ArrayList<>();
BarChartAdapter barChartAdapter;
int[] colors = {Color.GREEN, Color.CYAN, Color.MAGENTA, Color.RED };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.rv_bar_chart);
listData.add(new Data(8.0f,Color.GREEN));
listData.add(new Data(4.0f,Color.CYAN));
listData.add(new Data(2.0f,Color.MAGENTA));
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
barChartAdapter = new BarChartAdapter(listData);
recyclerView.setAdapter(barChartAdapter);
}
public class BarChartAdapter extends RecyclerView.Adapter<BarChartAdapter.MyViewHolder> {
ArrayList<Data> listData = new ArrayList<>();
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
LinearLayout layout;
public MyViewHolder(View v) {
super(v);
textView = v.findViewById(R.id.tv_chart_value);
layout = (LinearLayout) v.findViewById(R.id.lo_dynamic_view_container);
}
}
public BarChartAdapter(ArrayList<Data> listData) {
this.listData = listData;
}
#Override
public BarChartAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
View v = (View) LayoutInflater
.from(parent.getContext())
.inflate(R.layout.barchart_layout, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.setIsRecyclable(false);
holder.textView.setText(listData.get(position).value+"");
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
width = width - (100/width)*80;
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
TextView tv = new TextView(MainActivity.this);
tv.setLayoutParams(lparams);
tv.setWidth((int) Math.floor( getRatio(width, listData.get(position).value,getHighestValue(listData))));
float redious [] = { 0, 0, 8.3f, 8.5f, 8.2f, 8.9f, 0, 0 };
ShapeDrawable shape = new ShapeDrawable (new RoundRectShape(redious,null,null));
shape.getPaint().setColor(listData.get(position).color);
//shape.getPaint().setColor(colors[new Random().nextInt((colors.length-1) - 0 + 1) + 0]);
//shape.getPaint().setColor(Color.GREEN);
tv.setBackground(shape);
holder.layout.addView(tv);
}
#Override
public int getItemCount() {
return listData.size();
}
}
private float getRatio(int width, float value, float highestValue){
float result = 0;
result = ( (float)width/highestValue) * value;
Log.e("Result", "width: "+ width +" "+(int) Math.floor(result)+"");
return result;
}
private float getHighestValue(ArrayList<Data> listData){
float result = 0.0f;
if(listData!=null){
if(listData.size()>0){
for (int i = 0; i < listData.size(); i++) {
result = listData.get(i).value>result?listData.get(i).value:result;
}
}
}
return result;
}
class Data{
float value;
int color;
public Data(float value, int color) {
this.value = value;
this.color = color;
}
}
}
Screen Shoot
Full Project link on GitHub
RecyclerView by default, does come with a nice deletion animation, as long as you setHasStableIds(true) and provide correct implementation on getItemId.
Recently, I had added divider into RecyclerView via https://stackoverflow.com/a/27037230/72437
The outcome looks as following
https://www.youtube.com/watch?v=u-2kPZwF_0w
https://youtu.be/c81OsFAL3zY (To make the dividers more visible when delete animation played, I temporary change the RecyclerView background to red)
The dividers are still visible, when deletion animation being played.
However, if I look at GMail example, when deletion animation being played, divider lines are no longer visible. They are being covered a solid color area.
https://www.youtube.com/watch?v=cLs7paU-BIg
May I know, how can I achieve the same effect as GMail, by not showing divider lines, when deletion animation played?
The solution is fairly easy. To animate a decoration, you can and should use view.getTranslation_() and view.getAlpha(). I wrote a blog post some time ago on this exact issue, you can read it here.
Translation and fading off
The default layout manager will fade views out (alpha) and translate them, when they get added or removed. You have to account for this in your decoration.
The idea is simple:
However you draw your decoration, apply the same alpha and translation to your drawing by using view.getAlpha() and view.getTranslationY().
Following your linked answer, it would have to be adapted like the following:
// translate
int top = child.getBottom() + params.bottomMargin + view.getTranslationY();
int bottom = top + mDivider.getIntrinsicHeight();
// apply alpha
mDivider.setAlpha((int) child.getAlpha() * 255f);
mDivider.setBounds(left + view.getTranslationX(), top,
right + view.getTranslationX(), bottom);
mDivider.draw(c);
A complete sample
I like to draw things myself, since I think drawing a line is less overhead than layouting a drawable, this would look like the following:
public class SeparatorDecoration extends RecyclerView.ItemDecoration {
private final Paint mPaint;
private final int mAlpha;
public SeparatorDecoration(#ColorInt int color, float width) {
mPaint = new Paint();
mPaint.setColor(color);
mPaint.setStrokeWidth(width);
mAlpha = mPaint.getAlpha();
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
// we retrieve the position in the list
final int position = params.getViewAdapterPosition();
// add space for the separator to the bottom of every view but the last one
if (position < state.getItemCount()) {
outRect.set(0, 0, 0, (int) mPaint.getStrokeWidth()); // left, top, right, bottom
} else {
outRect.setEmpty(); // 0, 0, 0, 0
}
}
#Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
// a line will draw half its size to top and bottom,
// hence the offset to place it correctly
final int offset = (int) (mPaint.getStrokeWidth() / 2);
// this will iterate over every visible view
for (int i = 0; i < parent.getChildCount(); i++) {
final View view = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
// get the position
final int position = params.getViewAdapterPosition();
// and finally draw the separator
if (position < state.getItemCount()) {
// apply alpha to support animations
mPaint.setAlpha((int) (view.getAlpha() * mAlpha));
float positionY = view.getBottom() + offset + view.getTranslationY();
// do the drawing
c.drawLine(view.getLeft() + view.getTranslationX(),
positionY,
view.getRight() + view.getTranslationX(),
positionY,
mPaint);
}
}
}
}
Firstly, sorry for the massive answer size. However, I felt it necessary to include my entire test Activity so that you can see what I have done.
The issue
The issue that you have, is that the DividerItemDecoration has no idea of the state of your row. It does not know whether the item is being deleted.
For this reason, I made a POJO that we can use to contain an integer (that we use as both an itemId and a visual representation and a boolean indicating that this row is being deleted or not.
When you decide to delete entries (in this example adapter.notifyItemRangeRemoved(3, 8);), you must also set the associated Pojo to being deleted (in this example pojo.beingDeleted = true;).
The position of the divider when beingDeleted, is reset to the colour of the parent view. In order to cover up the divider.
I am not very fond of using the dataset itself to manage the state of its parent list. There is perhaps a better way.
The result visualized
The Activity:
public class MainActivity extends AppCompatActivity {
private static final int VERTICAL_ITEM_SPACE = 8;
private List<Pojo> mDataset = new ArrayList<Pojo>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for(int i = 0; i < 30; i++) {
mDataset.add(new Pojo(i));
}
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(new VerticalSpaceItemDecoration(VERTICAL_ITEM_SPACE));
recyclerView.addItemDecoration(new DividerItemDecoration(this));
RecyclerView.ItemAnimator ia = recyclerView.getItemAnimator();
ia.setRemoveDuration(4000);
final Adapter adapter = new Adapter(mDataset);
recyclerView.setAdapter(adapter);
(new Handler(Looper.getMainLooper())).postDelayed(new Runnable() {
#Override
public void run() {
int index = 0;
Iterator<Pojo> it = mDataset.iterator();
while(it.hasNext()) {
Pojo pojo = it.next();
if(index >= 3 && index <= 10) {
pojo.beingDeleted = true;
it.remove();
}
index++;
}
adapter.notifyItemRangeRemoved(3, 8);
}
}, 2000);
}
public class Adapter extends RecyclerView.Adapter<Holder> {
private List<Pojo> mDataset;
public Adapter(#NonNull final List<Pojo> dataset) {
setHasStableIds(true);
mDataset = dataset;
}
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_cell, parent, false);
return new Holder(view);
}
#Override
public void onBindViewHolder(final Holder holder, final int position) {
final Pojo data = mDataset.get(position);
holder.itemView.setTag(data);
holder.textView.setText("Test "+data.dataItem);
}
#Override
public long getItemId(int position) {
return mDataset.get(position).dataItem;
}
#Override
public int getItemCount() {
return mDataset.size();
}
}
public class Holder extends RecyclerView.ViewHolder {
public TextView textView;
public Holder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.text);
}
}
public class Pojo {
public int dataItem;
public boolean beingDeleted = false;
public Pojo(int dataItem) {
this.dataItem = dataItem;
}
}
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private final int[] ATTRS = new int[]{android.R.attr.listDivider};
private Paint mOverwritePaint;
private Drawable mDivider;
/**
* Default divider will be used
*/
public DividerItemDecoration(Context context) {
final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
mDivider = styledAttributes.getDrawable(0);
styledAttributes.recycle();
initializePaint();
}
/**
* Custom divider will be used
*/
public DividerItemDecoration(Context context, int resId) {
mDivider = ContextCompat.getDrawable(context, resId);
initializePaint();
}
private void initializePaint() {
mOverwritePaint = new Paint();
mOverwritePaint.setColor(ContextCompat.getColor(MainActivity.this, android.R.color.background_light));
}
#Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + mDivider.getIntrinsicHeight();
Pojo item = (Pojo) child.getTag();
if(item.beingDeleted) {
c.drawRect(left, top, right, bottom, mOverwritePaint);
} else {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
}
}
public class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration {
private final int mVerticalSpaceHeight;
public VerticalSpaceItemDecoration(int mVerticalSpaceHeight) {
this.mVerticalSpaceHeight = mVerticalSpaceHeight;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
outRect.bottom = mVerticalSpaceHeight;
}
}
}
The Activity Layout
<?xml version="1.0" encoding="utf-8"?>
<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"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:background="#android:color/background_light"
tools:context="test.dae.myapplication.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
The RecyclerView "row" Layout
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/text"
android:padding="8dp">
</TextView>
I think the ItemDecorator you use to draw a divider after every row is messing things up when swipe to delete is performed.
Instead of Using ItemDecorator to draw a Divider in a recyclerview, add a view at the end of your RecyclerView child layout design.which will draw a divider line like ItemDecorator.
<LinearLayout
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="wrap_content"
>
<!-- child layout Design !-->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#android:color/darker_gray"
android:layout_gravity="bottom"
/>
</Linearlayout>
I am creating a horisontal RecyclerView in my app.
It has to show 2 images on the screen at a time (so width of each image has to be 50% of the screen).
For now it works fine but each item consums all width of the screen.
Here is my code
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_main_ads);
LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(getActivity());
mLinearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(mLinearLayoutManager);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(tmp, R.layout.lv_main_screen);
mRecyclerView.setAdapter(adapter);
Here is layout of an item
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">
<ImageView
android:id="#+id/iv_main_ad"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:scaleType="fitXY"
android:src="#drawable/baner_gasoline"
/>
</LinearLayout>
As you can see I tried to use Layout_gravity="0.5",
But it doesn't help.
I tried to specify layout_width = ...dp but I can not get exactly half of the screen.
I am thinking of adding another ImageView into item layout, but in this case I will have troubles with the adapter, because I want to implemnt circled (infinity) horizontal listview
here is my adapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyHolder> {
private List<Integer> mImages;
private int itemLayout;
public RecyclerViewAdapter(ArrayList<Integer> imageResourceIds, int itemLayout) {
this.mImages = imageResourceIds;
this.itemLayout = itemLayout;
}
#Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false);
return new MyHolder(v);
}
#Override
public void onBindViewHolder(MyHolder holder, int position) {
holder.adIv.setImageResource(mImages.get(position));
}
#Override
public int getItemCount() {
return mImages.size();
}
public static class MyHolder extends RecyclerView.ViewHolder {
protected ImageView adIv;
private MyHolder(View v) {
super(v);
this.adIv = (ImageView) v.findViewById(R.id.iv_main_ad);
}
}
}
For You need to calculate the width of the screen and set the width dynamically below is the my code
Add below code in your ViewHolder initilisation
llImg = (LinearLayout) itemView.findViewById(R.id.llImg);
llImg.getLayoutParams().width = (int) (Utils.getScreenWidth(itemView.getContext()) / 2);
llImg.getLayoutParams().height = (int) (Utils.getScreenWidth(itemView.getContext()) / 2);
imgView = (ImageView) itemView.findViewById(R.id.imgView);
The Layout file is here
<LinearLayout
android:id="#+id/llImg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<ImageView
android:id="#+id/imgView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
Make one Utils.java
public static int getScreenWidth(Context context) {
if (screenWidth == 0) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenWidth = size.x;
}
return screenWidth;
}
Hope this will help you !
I have a Recyclerview that is managed by an adapter. For each item in the recycler I inflate a complex view that contains also a horizontal progressbar which takes the whole width of screen.
I have to position a baloon TextView with the percentage value (20% , 60% etc) that points to the progressbar like an indicator to the amount of progress. I tried using this code
int[] startPosition = new int[2];
Integer progresswidth;
WindowManager wm = (WindowManager) contextthis.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
progresswidth = size.x;
holder.horiz_progress.getLocationOnScreen(startPosition);
float exactvalue = (progresswidth * currentitem.getMatchPercent()) / 100;
startPosition[0] = startPosition[0] + Math.round(exactvalue);
startPosition[0] = startPosition[0] - holder.baloon_txt.getWidth() / 3 ;
startPosition[1] = startPosition[1] + 10;
holder.baloon_txt.setX(startPosition[0]);
holder.baloon_txt.setY(startPosition[1]);
But the problem is that holder.horiz_progress.getLocationOnScreen always returns 0 so I cannot position the balloon_txt.
I had a similar issue inside an activity and there i resolved it overriding OnWindowFocusChanged but this is inside the adapter so I don't know how to get it done.
EDIT
My current adapter code:
public class ResultsAdapter extends RecyclerView.Adapter<ResultsAdapter.ViewHolder>{
private List<ResultsItem> mResults;
private View mSelectedView;
private int mSelectedPosition;
Context contextthis;
android.os.Handler handler;
int[] startPosition = new int[2];
public ResultsAdapter(Context context,List<ResultsItem> resultsItemList) {
this.mResults = resultsItemList;
contextthis = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.results_item, null);
final ViewHolder viewHolder = new ViewHolder(v);
viewHolder.results_likeimg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
return viewHolder;
}
#Override
public void onBindViewHolder( final ViewHolder holder, int position) {
final ResultsItem currentitem = mResults.get(position);
//set Image
if(currentitem.getImageslist().get(0).getPicture() != null)
ImageLoader.getInstance().displayImage(currentitem.getImageslist().get(0).getPicture(), holder.results_img);
//baloon set
holder.baloon_txt.setText(currentitem.getMatchPercent() + "% " + "Match");
holder.horiz_progress.setProgress(currentitem.getMatchPercent());
final View view = holder.horiz_progress;
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
view.getLocationOnScreen(startPosition);
Integer progresswidth;
WindowManager wm = (WindowManager) contextthis.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
progresswidth = size.x;
float exactvalue = (progresswidth * currentitem.getMatchPercent()) / 100;
startPosition[0] = startPosition[0] + Math.round(exactvalue);
startPosition[0] = startPosition[0] - holder.baloon_txt.getWidth() / 3 ;
startPosition[1] = startPosition[1] + 10;
holder.baloon_txt.setX(startPosition[0]);
holder.baloon_txt.setY(startPosition[1]);
}
});
//logo
if(currentitem.getPriceslist().get(0).getSource() != null)
ImageLoader.getInstance().displayImage(currentitem.getPriceslist().get(0).getSource(), holder.results_logo_img);
//description
holder.description_txt.setText(currentitem.getDescription());
//price
holder.price_curr.setText(currentitem.getPriceslist().get(0).getCurrency());
holder.price_txt.setText(String.valueOf(currentitem.getPriceslist().get(0).getPrice()));
}
#Override
public int getItemCount() {
return mResults.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
ImageView results_img, results_dislikeimg, results_likeimg, results_logo_img;
ProgressBar horiz_progress;
TextView baloon_txt, price_txt, description_txt, buybtn, sharebtn, price_curr;
public ViewHolder(View view) {
super(view);
this.results_img = (ImageView) view.findViewById(R.id.resultsitem_img);
this.results_dislikeimg = (ImageView) view.findViewById(R.id.results_item_dislike);
this.results_likeimg = (ImageView) view.findViewById(R.id.resultsitem_like);
this.results_logo_img = (ImageView) view.findViewById(R.id.logoimg);
this.horiz_progress = (ProgressBar) view.findViewById(R.id.progressBar_horizontal);
this.baloon_txt = (TextView) view.findViewById(R.id.baloonMatch_txt);
this.price_txt = (TextView) view.findViewById(R.id.price_txt);
this.description_txt = (TextView) view.findViewById(R.id.description_txt);
this.buybtn = (TextView) view.findViewById(R.id.buybtn);
this.sharebtn = (TextView) view.findViewById(R.id.sharebtn);
this.price_curr = (TextView) view.findViewById(R.id.price_curr);
}
}
}
getLocation() returns 0 because the view has not been laid out yet. You need to set a layout listener:
final View view = holder.horiz_progress;
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Do what you need to do here.
// Then remove the listener:
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
I'm stuck with an issue about changing Recycler height based on its total items.
What I have tried is to use Layout Param like this:
ViewGroup.LayoutParams params = myRecyclerView.getLayoutParams();
params.height = itemHeight * numberOfItem;
myRecyclerView.requestLayout();
or
ViewGroup.LayoutParams params = new RecyclerView.LayoutParams(..WRAP_CONTENT, ...WRAP_CONTENT);;
params.height = itemHeight * numberOfItem;
myRecyclerView..setLayoutParams(params);
But it didn't work.
How can I do it ? Please help me !
You should use LayoutParams of parent's view in setLayoutParams(params).
For example:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<android.support.v7.widget.RecyclerView
android:id="#+id/images"
android:layout_width="wrap_content"
android:layout_height="360dp"
>
</android.support.v7.widget.RecyclerView>
</Relativelayout>
Change LayoutParams in the code.
RelativeLayout.LayoutParams lp =
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 500);
recyclerView.setLayoutParams(lp);
I tried this. It worked. May be help.
#Override
public void onBindViewHolder(FeedListRowHolder feedListRowHolder, int i) {
//this change height of rcv
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.height =80; //height recycleviewer
feedListRowHolder.itemView.setLayoutParams(params);
FeedItem feedItem = feedItemList.get(i);
Picasso.with(mContext).load(feedItem.getThumbnail())
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(feedListRowHolder.thumbnail);
feedListRowHolder.title.setText(Html.fromHtml(feedItem.getTitle()));
feedListRowHolder.itemView.setActivated(selectedItems.get(i, false));
feedListRowHolder.setClickListener(new FeedListRowHolder.ClickListener() {
public void onClick(View v, int pos, boolean isLongClick) {
if (isLongClick) {
// View v at position pos is long-clicked.
String poslx = pos + "";
Toast.makeText(mContext, "longclick " + poslx, Toast.LENGTH_SHORT).show();
} else {
// View v at position pos is clicked.
String possx = pos + "";
Toast.makeText(mContext, "shortclick " + possx, Toast.LENGTH_SHORT).show();
toggleSelection(pos);
}
}
});
}
If you just want your recycler view to size automatically as per number of items then, why don't you put RecyclerView height as wrap_content.
If you have multiple ScrollView in layout then try wrapping RecyclerView in NestScrollView and set it's height as wrap_content too.
code :
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
Although the question was asked quite some time ago, I figured some might find this answer helpful.
I have a RecyclerView with adapter. The height is set in onBindViewHolder method of the adapter:
Layout:
<android.support.v7.widget.RecyclerView
android:id="#+id/container"
...
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
public abstract static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
public abstract void setFixedHeight();
}
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new ViewHolder(view) {
#Override
public void setFixedHeight() {
// magic happening here
ViewGroup.LayoutParams parentParams = parent.getLayoutParams();
parentParams.height =
((RecyclerView) parent).computeVerticalScrollRange()
+ parent.getPaddingTop()
+ parent.getPaddingBottom();
parent.setLayoutParams(parentParams);
}
};
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setFixedHeight();
}
// other methods here
}
Setting adapter:
recyclerView.setAdapter(new MyAdapter(...));
Note: Use((RecyclerView) parent).computeHorizontalScrollRange() with horizontal scroll
This code works I am sure about it
ViewGroup.LayoutParams params=recyclerview.getLayoutParams();
params.height=100;
recyclerview.setLayoutParams(params);
The other thing you could do is make a linear layout as the parent of the recycler view and then increase the height dynamically for the parent view
Consider the following XML below
<LinearLayout
android:id="#+id/yourLayoutId">
<RecyclerView android:width="match_parent" android:height="wrap_content">
</RecyclerView>
</LinearLayout
Consider the following code
LinearLayout layout = (LinearLayout)findViewById(R.id.yourLayoutId);
LinearLayout.LayoutParams lp = (LayoutParams) layout.getLayoutParams();
lp.height = 100;