【问题标题】:How to rotate TextView without clipping its bounds?如何在不剪裁边界的情况下旋转 TextView?
【发布时间】:2013-01-02 05:12:46
【问题描述】:

我正在尝试使用canvas.rotate() 旋转我的TextView 子类:

canvas.save();

final int w = getWidth();
final int h = getHeight();

float px = w/2f;
float py = h/2f;
canvas.rotate(mAngle, px, py);

super.draw(canvas);

canvas.restore();

TextView 被旋转了,但是我的视图的边界被剪掉了:

我知道这是因为我的视图的大小 - 它在旋转过程中没有改变,而它应该改变。但是,如果我在onMeasure 中更改宽度\高度,问题仍然存在——我正在使用LayoutParams.WRAP_CONTENT,所以TextView 只需根据setMeasuredDimensions 中提供的值更改它的大小。

我该如何解决这个问题?

【问题讨论】:

  • 尝试设置android:clipChildren=false;和 android:clipToPadding=false;到 TextView 的父级。
  • @Leonidos 它在旋转时会导致奇怪的伪影。另外,我必须剪辑一些视图,所以我不能只设置clipChildren=false

标签: android android-canvas


【解决方案1】:

好的,如果您无法在当前视图层次结构中旋转 textView,则应该在另一个视图层次结构中对其进行动画处理。

为您的 textView 创建一个位图表示。使用 ImageView 等该位图的支架。将 imageView 连接到另一个布局,该布局位于顶部且不会被裁剪。隐藏你的文本视图。在 ImageView 上运行动画。动画完成后,更新 textView 表示,显示 textView 并删除 ImageView。

我找不到您想要的确切代码示例,但请查看this one。交集的地方是:

mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
mWindowManager.addView(YOUR_VIEW_WITH_ANIMATION, mWindowParams);

【讨论】:

    【解决方案2】:

    您可以查看https://github.com/grantland/android-autofittextview 尤其是它的 refitText() 方法。

    你的 Textview 的旋转应该最终导致 onMeasure() 方法的调用,所有的魔法都从这里开始。

    【讨论】:

      【解决方案3】:

      我认为这里的全部问题在于您使用的是 WRAP_CONTENT。当您这样做时,视图的剪辑矩形是文本内容的大小。解决问题的最简单方法是使用填充。像这样的东西,对我来说很好用:

      <com.example.twistedtext.TwistedTextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:padding="30dp"
          android:gravity="center"
          android:layout_centerHorizontal="true"
          android:layout_centerVertical="true"
          twistedtext:rotation="30.0f"
          android:text="@string/hello_world" />
      

      当然,如果您这样做,您必须为每个内容选择稍微不同的填充。如果您不能这样做,请覆盖 onMeasure,这样就可以完成 TextView 的 onMeasure 所做的工作,然后根据需要添加相应的填充以进行旋转。

      稍后添加: 实际上,弄清楚这一点很有趣。我有以下 onMeasure,效果很好:

      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
          int w = getMeasuredWidth();
          int h = getMeasuredHeight();
          w = (int) Math.round(w * cosA + h * sinA);
          h = (int) Math.round(h * cosA + w * sinA);
          setMeasuredDimension(w, h);
      }
      

      唯一剩下的问题是文本会根据旋转前的尺寸进行换行。你也必须解决这个问题......

      sinA 和 cosA 在设置 mAngle 时计算。

      【讨论】:

        【解决方案4】:

        G. Blake Meike 提供的初步解决方案是一个很好的开始方式,但随之而来的是很多问题。

        要克服问题,还有另一种方法。这很简单,但通常不应该使用(因为我刚刚从原始 android 源中删除了对我来说不必要的东西)。要控制具体View 的绘制,您可以覆盖其父级的drawChild 方法(是的,您需要自己的ViewGroup 子类或更具体的东西,例如FrameLayout)。这是我的解决方案的一个示例:

        @Override
        protected boolean drawChild(Canvas canvas, View child, long time) {
            //TextBaloon - is view that I'm trying to rotate
            if(!(child instanceof TextBaloon)) {
                return super.drawChild(canvas, child, time);
            }
        
            final int width = child.getWidth();
            final int height = child.getHeight();
        
            final int left = child.getLeft();
            final int top = child.getTop();
            final int right = left + width;
            final int bottom = top + height;
        
            int restoreTo = canvas.save();
        
            canvas.translate(left, top);
        
            invalidate(left - width, top - height, right + width, bottom + height);
            child.draw(canvas);
        
            canvas.restoreToCount(restoreTo);
        
            return true;
        }
        

        主要想法是我将非剪辑画布授予孩子。

        【讨论】:

        • 啊!我被抢了!这不是一个解决方案,这是一个黑客!哦,好吧,解决它很有趣。
        • @G.BlakeMeike 不完全是 hack :) 这是drawChild 方法的全部要点 - 控制绘图。但是,您的回答最终会导致更“正确”的解决方案,所以我会给您一个赏金)
        • 非常感谢德米特里。事实证明,您需要重写以修复文本布局 TextView.makeNewLayout 的方法是受保护的,但 @hide。根据新的边界,很难防止文本被重新包装。无赖。
        • 等等,我想我只是吐在嘴里。因此,除非您围绕中心点旋转,否则您无法旋转 ImageView 而不会对其进行裁剪。一定有一个很好的理由,但它看起来很愚蠢。我不想覆盖 onDraw、添加填充或任何其他此类愚蠢行为。来吧,Android 只需在父视图上旋转位图并根据需要移动/调整大小!
        • 我想在不裁剪的情况下旋转 ImageView,这是唯一对我有用的解决方案。这太不可思议了。 Android 应该更容易。
        猜你喜欢
        • 1970-01-01
        • 2012-11-08
        • 1970-01-01
        • 2018-12-03
        • 2017-10-20
        • 1970-01-01
        • 2017-12-30
        • 1970-01-01
        • 2011-01-11
        相关资源
        最近更新 更多