【问题标题】:How to overlay list item text color in specific region?如何在特定区域覆盖列表项文本颜色?
【发布时间】:2013-07-03 20:05:31
【问题描述】:

假设我们有自定义的ListView,它通过在其中绘制一些矩形来扩展onDraw() 方法。

class Listpicker extends ListView {
//..Some other methods here..//
    @Override
    protected void onDraw(android.graphics.Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawBitmap(glassPickerBitmap, null, glassRect, semiTransparrentPaint);
    }
}

绘制的位图代表某种玻璃,它是矩形,宽度等于列表视图的宽度和一些高度。我想要的是当列表项滚动到此矩形时,用于绘制文本的颜色(并非所有具有背景等的项)将更改为另一种颜色。因此,例如,当列表项适合以便只有一半高度的文本适合 glassPickerBitmap 时,列表项的外部部分应保持其序号颜色,glassPickerBitmap 内部的部分应更改其文本颜色。列表项是没有任何背景的简单 TextView。

如何做到这一点?也许任何ColorFilters 分配给Paint?但是哪里? onDraw()Listview 方法甚至不会在 ListView 滚动时被调用...这可以在自定义视图中完成吗,例如,这将是 ListView 的项目?或者可能是一些Color/Shader/不知道这里还能用什么叠加,但是在哪里

编辑(添加图片示例):

以下是来自真实应用的一些裁剪示例。有 2 个ListViews:一个在左侧,另一个在右侧。玻璃是灰色的矩形。现在,左侧列表已选择“美国美元” 货币。我以这种方式向右滚动ListView,该选择介于 USDAfghan Afghani 之间。现在,我想要的是左侧ListView 中的 USD 货币将被绘制为红色(现在确切的颜色无关紧要,我稍后会将其更改为有意义的东西)并且,在同时,右侧 ListView 中 "United States Dollar" 的底部和 "Afghan Afghani" 的顶部也将被绘制成相同的红色。

这种颜色更改应该以动态方式进行 - 在列表滚动期间,仅应为玻璃矩形下方的文本部分更改颜色。

*好的,这里的欧元和美元是用非标准青色绘制的特殊货币。问题至少是关于带有 white 颜色的文本。但是,如果也可以更改青色,那就太好了。

【问题讨论】:

  • View.setWillNotDraw (boolean willNotDraw) 应该在ListView 中调用onDraw。这是否能让你实现你想要的东西是值得商榷的。然而,有趣的问题。
  • @Prizoff 能否提供两张图片(一张是普通物品,另一张是玻璃下方物品)?
  • @Prizoff 酷,让我看看
  • @Prizoff 你能看看我的回答吗?
  • @EvelioTarazona 我一定会好好研究它,只是不久之后,现在不能做任何编程工具,还有一些其他与 IT 无关的问题。乍一看,它应该可以工作,谢谢!

标签: java android listview colors overlay


【解决方案1】:

首先,保留一个备用的位图和画布:

class Listpicker extends ListView {
    Bitmap bitmapForOnDraw = null;
    Canvas canvasForOnDraw = null;

确保尺寸合适:

    @override
    protected void onSizeChanged (int w, int h, int oldw, int oldh) {
        if (bitmapForOnDraw != null) bitmapForOnDraw.recycle();
        bitmapForOnDraw = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        canvasForOnDraw = new Canvas(bitmapForOnDraw);
    }

当我们开始绘制列表时:

    @override
    protected void onDraw(android.graphics.Canvas realCanvas) {
        // Put the list in place
        super.onDraw(realCanvas);

        // Now get the same again
        canvasForOnDraw.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
        super.onDraw(canvasForOnDraw);
        // But now change the colour of the white text
        canvasForOnDraw.drawColor(0xffff00ff, PorterDuff.Mode.MULTIPLY);

        // Copy the different colour text into the right place
        canvas.drawBitmap(bitmapForOnDraw, glassRect, glassRect overwritePaint);

        // finally, put the box on.
        canvas.drawBitmap(glassPickerBitmap, null, glassRect, semiTransparrentPaint);
    }

【讨论】:

    【解决方案2】:

    正如您在他们的实现中所知道的那样,他们使用并更新了ListAdapter 中的固定位置,因此他们更新了相应匹配的View,这对我来说是最简单、最简单的方法,但您不需要'不要得到半彩色文本,我认为你仍然想要它:)


    所以这可能是我给出的最糟糕的答案之一,对此感到抱歉,我可能会重新审视这个问题,或者希望有人能指出更好的解决方案

    您可以在以下位置看到一个模糊的演示:

    http://telly.com/Y98DS5

    肮脏的方式:

    • 用正确的ColorMatrixColorFilter 创建一个Paint,为了回答这个问题,我只是去饱和,你必须为ColorMatrix 找出你的5x4 矩阵,以获得你正在寻找的青色。此外,您还需要一些Rects 来在下面绘制时定义源和目标。
    • 创建一个屏幕外BitmapCanvas 用于绘制列表,这是在onSizeChanged 中完成的,所以我们有适当的视图布局值,在这里你可以开始注意到脏污,因为你必须这样做分配一个和ListView 一样大的Bitmap,这样你就可以得到OutOfMemoryException
    • 覆盖draw 以使用您的屏幕外Canvas 并让ListView 绘制到它,然后您可以将Bitmap 绘制到给定的Canvas,这将照常绘制您的列表,然后只绘制Bitmap 的一部分将使用我们之前定义的 Paint 以不同方式绘制,您将获得这些像素的过度绘制。
    • 最后绘制您的预制玻璃Bitmap,我建议您使用 n-patch(9-patch),这样它可以在屏幕和密度范围内缩放并看起来清晰,然后您会为这些像素获得更多的过度绘制。

    整个蛋糕长这样:

    public class OverlayView extends ListView {
      private RectF mRect;
      private Rect mSrcRect;
      private Paint mPaint;
    
      private Canvas mCanvas;
      private Bitmap mBitmap;
      private float mY;
      private float mItemHeight;
    
      public OverlayView(Context context) {
        super(context);
    
        initOverlay();
      }
    
      public OverlayView(Context context, AttributeSet attrs) {
        super(context, attrs);
    
        initOverlay();
      }
    
      public OverlayView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    
        initOverlay();
      }
    
      private void initOverlay() {
        // DO NOT DO THIS use attrs
        final Resources res = getResources();
        mY = res.getDimension(R.dimen.overlay_y);
        mItemHeight = res.getDimension(R.dimen.item_height);
        //
        mRect = new RectF();
        mSrcRect = new Rect();
        mPaint = new Paint();
    
        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.setSaturation(0);
        mPaint.setColorFilter( new ColorMatrixColorFilter(colorMatrix) );
      }
    
      @Override
      public void draw(Canvas canvas) {
        super.draw(mCanvas);
        canvas.drawBitmap(mBitmap, 0, 0, null);
    
        canvas.drawBitmap(mBitmap, mSrcRect, mRect, mPaint);
      }
    
      @Override
      protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    
        mRect.set(0, mY, w, mY + mItemHeight);
        mRect.roundOut(mSrcRect);
    
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
      }
    }
    

    也就是说,我希望你最终能得到一个更清洁的解决方案,即使你没有得到那种一半一半的性感:)

    【讨论】:

    • 是的,我使用 Max OS X 正是 Maverixks
    • getDrawingCache()代替单独的位图怎么样?
    • @S.D.是的,你也可以使用它,实际上做类似的事情,只是带有一些额外的怪癖,比如现在不推荐使用的最大缓存大小,空白位图,其他人也可以使用该绘图缓存,我记得你应该只使用它对于软件层,在这种情况下(并非总是)管理自己的缓存可以让您控制并让您高枕无忧:您肯定知道这是您的错;)无论如何,正如我之前提到的那样,这很脏,您应该避免它(最坏的情况)推销员)
    • @EvelioTarazona 这绝对有效,谢谢!首先,我试图通过覆盖 onDraw() 而不是 draw() 来让它工作起来。但是当我注意到这一点时 - 事情变得好多了。 :)
    • @Prizoff 很高兴,上次我做了一个有人说是“等待有人用斧头跳出来”
    猜你喜欢
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    • 2018-11-12
    • 2012-06-16
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多