【问题标题】:Android: Draw a ProgressBar on canvas not workingAndroid:在画布上绘制进度条不起作用
【发布时间】:2017-05-16 13:11:01
【问题描述】:

我正在尝试在画布上绘制 ProgressBar。我怀疑它不会自己绘制,因为 onAttachedToWindow 没有被调用......?如果我尝试绘制 TextView,它会正常显示和绘制。我需要在画布上绘制 ProgressBar,因为在 RecyclerView 加载时没有其他方法可以将其显示为装饰器https://yoda.entelect.co.za/view/9627/how-to-android-recyclerview-item-decorations

此活动只是演示如何绘制 ProgressBar。

public class DrawingActivity extends Activity {

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Rect rect = new Rect();
    rect.set(0, 0, 500, 500);

    Bitmap bitmap = Bitmap.createBitmap(700, 700, Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);

    //Make a new view and lay it out at the desired Rect dimensions
    //        TextView view = new TextView(this);
    //        view.setText("This is a custom drawn textview");
    ProgressBar view = new ProgressBar(this, null, android.R.attr.progressBarStyle);

    //Measure the view at the exact dimensions (otherwise the text won't center correctly)
    int widthSpec = MeasureSpec.makeMeasureSpec(rect.width(), MeasureSpec.EXACTLY);
    int heightSpec = MeasureSpec.makeMeasureSpec(rect.height(), MeasureSpec.EXACTLY);
    view.measure(widthSpec, heightSpec);

    //Lay the view out at the rect width and height
    view.layout(0, 0, rect.width(), rect.height());

    //Translate the Canvas into position and draw it
    canvas.save();
    canvas.translate(rect.left, rect.top);
    view.draw(canvas);
    canvas.restore();

    //To make sure it works, set the bitmap to an ImageView
    ImageView imageView = new ImageView(this);
    imageView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    imageView.setScaleType(ScaleType.CENTER);
    imageView.setImageBitmap(bitmap);

    setContentView(imageView);

    // force the invalidation of the view
    ViewCompat.postInvalidateOnAnimation(view);
}
}

编辑:

为 RecyclerView 添加 Layout 装饰器:

public class LayoutItemDecorationTest extends RecyclerView.ItemDecoration {

private View view;
@LayoutRes
private int layoutRes;
private ItemPosition itemPosition;

public LayoutItemDecorationTest(@LayoutRes int layoutRes, ItemPosition position) {
    this.layoutRes = layoutRes;
    this.itemPosition = position;
}

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    super.getItemOffsets(outRect, view, parent, state);

    // view needs to be instantiated here, otherwise view animation doesn't work properly
    this.view = View.inflate(parent.getContext(), layoutRes, null);

    // adapter items count
    int count = parent.getAdapter().getItemCount();
    final int position = parent.getChildAdapterPosition(view);
    int height = view.getMeasuredHeight();

    if (itemPosition == ItemPosition.ALL) {
        outRect.set(0, 0, 0, height);
    } else if (itemPosition == ItemPosition.FIRST) {
        if (position == 0) {
            outRect.set(0, 0, 0, height);
        }
    } else if (itemPosition == ItemPosition.LAST) {
        if (position == count - 1) {
            outRect.set(0, 0, 0, height);
        }
    }
}

/**
 * Using onDrawOver to overlay any other existing decorators below
 */
@Override
public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
    canvas.save();

    // adapter items count
    int count = parent.getAdapter().getItemCount();

    // iterate through visible children
    int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {
        final View child = parent.getChildAt(i);
        int position = parent.getChildAdapterPosition(child);

        if (itemPosition == ItemPosition.ALL) {
            drawView(canvas, this.view, parent, child);
        } else if (itemPosition == ItemPosition.FIRST) {
            if (position == 0) {
                drawView(canvas, this.view, parent, child);
            }
        } else if (itemPosition == ItemPosition.LAST) {
            if (position == count - 1) {
                drawView(canvas, this.view, parent, child);
            }
        }
    }
    canvas.restore();

    // animation stops if we don't invalidate on the next animation time step
    ViewCompat.postInvalidateOnAnimation(parent);
}

private void drawView(Canvas canvas, View view, View parent, View child) {
    RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

    // canvas translation coordinates
    int left = parent.getPaddingLeft();
    int top = child.getBottom() + params.bottomMargin;

    // canvas must be translated to the correct location, otherwise view will be drawn on 0,0
    canvas.translate(left, top);

    // view must be measure and layout
    view.measure(MeasureSpec.getSize(child.getMeasuredWidth()), MeasureSpec.getSize(child.getMeasuredHeight()));
    view.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());

    // draw the view on canvas
    view.draw(canvas);
}
}

【问题讨论】:

  • 只需将 ProgressBar 添加到您的 RecyclerViews 项目视图中
  • 我想避免这样做,因为我想要一个干净的项目布局。这也意味着我应该对每个项目的状态负责,这就是我试图摆脱的。
  • 所以创建一个自定义RecyclerView.Adapter,添加ProgressBar并将其用作适配器的基类 - 所以您需要做的就是将... extends RecyclerView.Adapter&lt;...更改为... extends MyAdapter&lt;...
  • 如果你想使用装饰器然后在Canvas级别上使用它,直接进行绘制(而不使用任何分离的ProgressBar),只需像这样绘制Drawables:pastebin.com/QV9MsPjg
  • 试一试,当然需要根据自己的需要进行调整

标签: android canvas progress-bar draw android-progressbar


【解决方案1】:

ProgressBar 需要调用它的 startAnimation() 方法来开始显示微调器。

从 ProgressBar 源码可以看出,这个方法是从 onAttachedToWindow() 调用的。

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    if (mIndeterminate) {
        startAnimation();
    }
 ...
}

要调用这个方法 ProgressBar 应该被添加到父布局中。

root.addView(progressBar)

当然,ProgressBar 可能是从 xml 扩展而来的,你不再需要手动调用 measure(...) 和 layout(...) 方法,因为它们会在添加 ProgressBar 时自动调用到根布局。

LayoutInflater.from(context).inflate(R.layout.progress, parent, false)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 2012-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    相关资源
    最近更新 更多