2

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);

    }
}

}

Stef_ro89
  • 81
  • 1
  • 10

1 Answers1

3

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);
    }

});
natario
  • 24,954
  • 17
  • 88
  • 158
  • Should I put this in the OnCreateViewHolder? Because AFAIK OnBindViewHolder is called every time the view is recycled and I can lose the position – Stef_ro89 Oct 05 '15 at 14:05
  • You should put this onBind, onCreate is not enough. However I believe that your approach is a little flawed - recyclerview can scroll, so getLocationOnScreen() is not a reliable measure. See if it works. – natario Oct 05 '15 at 17:20
  • Yes. I found out that is not a good solution with getLocationOnScreen(). But how can I make this work? I need to put that indicator on every item relative to the value of currentitem.getMatchPercent(). Please give me a hint. Thanks – Stef_ro89 Oct 06 '15 at 06:59
  • 1
    One of the dimension (the y I guess) is fixed: above/beyond the progress bar. So you can just create a baloon view above/beyond the progress bar in XML. Then here you need to set the other dimension based on getMatchPercent(). For that you might try getLocationOnScreen() or some other approach. – natario Oct 06 '15 at 08:33
  • I managed to do it with @m val 's ideea. I fixed the y position from xml and calculated the x position based on the whole screen width (the progressbar takes the whole width) and the getMatchPercent() value. Thank you very much for your help. I'll set this as the accepted answer. – Stef_ro89 Oct 06 '15 at 09:09