【问题标题】:how to rotate text using canvas in Android如何在 Android 中使用画布旋转文本
【发布时间】:2011-08-10 05:24:06
【问题描述】:

我在 android 中使用画布绘制了一个饼图,并使用下面的代码在该饼图的每个切片上绘制了一个文本(在路径上绘制弧),现在我想绘制文本长度,即从中心到结束每个切片的,所以如何使用起始角和扫角来旋转圆弧。

p.addArc(mEventsRect, fStartAngle, fSweepAngle);
mBgPaints.setColor(iTextColor);
canvas.drawTextOnPath(sTextValue, p, fHOffSet, fVOffSet, mBgPaints);

【问题讨论】:

  • 一张图抵千言
  • 嘿,dev_android,如果你用不同的文本解决了这个旋转的圆圈,那么你能否给我你的示例代码,因为我很沮丧很多天都没有成功。实际上我正在尝试半圈。请帮忙。
  • 嗨 dev_android 。我也有同样的要求。我已经动态划分了一个圆圈,但我必须将单个文本绑定到每个弧,并按照您的要求进行对齐。但我什至没有将它们绑定在单独的弧线中。能否请您提供代码或示例来帮助我。

标签: android canvas path geometric-arc


【解决方案1】:

你可以试试这个sn-p:(来自:http://www.helloandroid.com/tutorials/how-use-canvas-your-android-apps-part-2

int x = 75;
int y = 185;
paint.setColor(Color.GRAY);
paint.setTextSize(25);
String rotatedtext = "Rotated helloandroid :)";

//Draw bounding rect before rotating text:

Rect rect = new Rect();
paint.getTextBounds(rotatedtext, 0, rotatedtext.length(), rect);
canvas.translate(x, y);
paint.setStyle(Paint.Style.FILL);

canvas.drawText(rotatedtext , 0, 0, paint);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(rect, paint);

canvas.translate(-x, -y);


paint.setColor(Color.RED);
canvas.rotate(-45, x + rect.exactCenterX(),y + rect.exactCenterY());
paint.setStyle(Paint.Style.FILL);
canvas.drawText(rotatedtext, x, y, paint);

【讨论】:

  • 我猜它会是这样的:centerOfCircle+radius*cos(angleOfThePie)/2
  • 在您的代码中 x 和 y 点是固定的,我需要 x 和 y 动态,即为每个饼图切片使用起始角和扫描角?
  • angleOfThePie 应该是介于你的角度之间的东西,当然 x 使用 cos,y 使用 sin
  • 拜托,您并没有说什么有效或无效。您的问题是什么!希望有 3 个人看到您需要的所有信息都在那里。请考虑接受或解释您的问题,以便我提供帮助!
  • 我很久以前就尝试过你的方法。我可以提醒的是,文本的放置方式不正确。我觉得计算有问题。
【解决方案2】:

也许这会对你有所帮助,, 这里 39.5 是半径,这将在 mdpi 屏幕上完美显示结果

 protected void onDraw(){
        canvas.save();
    PointF pf = PointOnCircle(35f, 45f, new PointF(39.5f, 39.5f));
            canvas.rotate(-45, pf.x, pf.y);
            canvas.drawText("67%", pf.x, pf.y, red);//23.5
            canvas.restore();
            canvas.save();
            PointF pfa = PointOnCircle(35f, 135f, new PointF(39.5f, 39.5f));
            canvas.rotate(45, pfa.x, pfa.y);
            canvas.drawText("33%", pfa.x, pfa.y, red);//23.5
            canvas.restore();
            canvas.save();
            pfa = PointOnCircle(27.5f, 225f, new PointF(39.5f, 39.5f));
            canvas.rotate(-45, pfa.x, pfa.y);
            canvas.drawText("45%", pfa.x, pfa.y, red);//23.5
            canvas.restore();
            canvas.save();
            pfa = PointOnCircle(27.5f, 315f, new PointF(39.5f, 39.5f));
            canvas.rotate(45, pfa.x, pfa.y);
            canvas.drawText("55%", pfa.x, pfa.y, red);//23.5

            canvas.restore();}

    protected static final PointF PointOnCircle(float radius, float angleInDegrees, PointF origin) {
            // Convert from degrees to radians via multiplication by PI/180        
            float x = (float) (radius * Math.cos(angleInDegrees * Math.PI / 180F)) + origin.x;
            float y = (float) (radius * Math.sin(angleInDegrees * Math.PI / 180F)) + origin.y;

            return new PointF(x, y);
        }

【讨论】:

    【解决方案3】:

    在这个库https://github.com/Ken-Yang/AndroidPieChart 的帮助下,经过两天的搜索,我终于做到了 在我的朋友和大量搜索的帮助下完成文本居中的方程式

    在 MainActivity onCreate 或 oncreateView 上(如果您使用片段):

    PieChart pie = (PieChart) rootView.findViewById(R.id.pieChart);
    
                ArrayList<Float> alPercentage = new ArrayList<Float>();
                alPercentage.add(2.0f);
                alPercentage.add(8.0f);
                alPercentage.add(20.0f);
                alPercentage.add(10.0f);
                alPercentage.add(10.0f);
                alPercentage.add(10.0f);
                alPercentage.add(10.0f);
                alPercentage.add(10.0f);
                alPercentage.add(10.85f);
                alPercentage.add(9.15f);
                try {
                    // setting data
                    pie.setAdapter(alPercentage);
    
                    // setting a listener
                    pie.setOnSelectedListener(new OnSelectedLisenter() {
                        @Override
                        public void onSelected(int iSelectedIndex) {
                            Toast.makeText(getActivity(),
                                    "Select index:" + iSelectedIndex,
                                    Toast.LENGTH_SHORT).show();
                        }
                    });
                } catch (Exception e) {
                    if (e.getMessage().equals(PieChart.ERROR_NOT_EQUAL_TO_100)) {
                        Log.e("kenyang", "percentage is not equal to 100");
                    }
                }
    
    
    
    public class PieChart extends View {
    
        public interface OnSelectedLisenter {
            public abstract void onSelected(int iSelectedIndex);
        }
    
        private OnSelectedLisenter onSelectedListener = null;
    
        private static final String TAG = PieChart.class.getName();
        public static final String ERROR_NOT_EQUAL_TO_100 = "NOT_EQUAL_TO_100";
        private static final int DEGREE_360 = 360;
        private static String[] PIE_COLORS = null;
        private static int iColorListSize = 0;
        ArrayList<Float> array;
        private Paint paintPieFill;
        private Paint paintPieBorder;
        private Paint paintCenterCircle;
        private ArrayList<Float> alPercentage = new ArrayList<Float>();
        private int mCenterX = 320;
        private int mCenterY = 320;
        private int iDisplayWidth, iDisplayHeight;
        private int iSelectedIndex = -1;
        private int iCenterWidth = 0;
        private int iShift = 0;
        private int iMargin = 0; // margin to left and right, used for get Radius
        private int iDataSize = 0;
        private Canvas canvas1;
        private RectF r = null;
        private RectF centerCircle = null;
        private float fDensity = 0.0f;
        private float fStartAngle = 0.0f;
        private float fEndAngle = 0.0f;
        float fX;
        float fY;
    
        public PieChart(Context context, AttributeSet attrs) {
            super(context, attrs);
            PIE_COLORS = getResources().getStringArray(R.array.colors);
            iColorListSize = PIE_COLORS.length;
            array = new ArrayList<Float>();
            fnGetDisplayMetrics(context);
            iShift = (int) fnGetRealPxFromDp(30);
            iMargin = (int) fnGetRealPxFromDp(40);
            centerCircle = new RectF(200, 200, 440, 440);
            // used for paint circle
            paintPieFill = new Paint(Paint.ANTI_ALIAS_FLAG);
            paintPieFill.setStyle(Paint.Style.FILL);
            // used for paint centerCircle
            paintCenterCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
            paintCenterCircle.setStyle(Paint.Style.FILL);
            paintCenterCircle.setColor(Color.WHITE);
            // used for paint border
            paintPieBorder = new Paint(Paint.ANTI_ALIAS_FLAG);
            paintPieBorder.setStyle(Paint.Style.STROKE);
            paintPieBorder.setStrokeWidth(fnGetRealPxFromDp(3));
            paintPieBorder.setColor(Color.WHITE);
            Log.i(TAG, "PieChart init");
    
        }
    
        // set listener
        public void setOnSelectedListener(OnSelectedLisenter listener) {
            this.onSelectedListener = listener;
        }
    
        float temp = 0;
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            Log.i(TAG, "onDraw");
            float centerX = (r.left + r.right) / 2;
            float centerY = (r.top + r.bottom) / 2;
            float radius1 = (r.right - r.left) / 2;
            radius1 *= 0.5;
            float startX = mCenterX;
            float startY = mCenterY;
            float radius = mCenterX;
            float medianAngle = 0;
            Path path = new Path();
    
            for (int i = 0; i < iDataSize; i++) {
    
                // check whether the data size larger than color list size
                if (i >= iColorListSize) {
                    paintPieFill.setColor(Color.parseColor(PIE_COLORS[i
                            % iColorListSize]));
                } else {
                    paintPieFill.setColor(Color.parseColor(PIE_COLORS[i]));
                }
    
                fEndAngle = alPercentage.get(i);
    
                // convert percentage to angle
                fEndAngle = fEndAngle / 100 * DEGREE_360;
    
                // if the part of pie was selected then change the coordinate
                if (iSelectedIndex == i) {
                    canvas.save(Canvas.MATRIX_SAVE_FLAG);
                    float fAngle = fStartAngle + fEndAngle / 2;
                    double dxRadius = Math.toRadians((fAngle + DEGREE_360)
                            % DEGREE_360);
                    fY = (float) Math.sin(dxRadius);
                    fX = (float) Math.cos(dxRadius);
                    canvas.translate(fX * iShift, fY * iShift);
                }
    
                canvas.drawArc(r, fStartAngle, fEndAngle, true, paintPieFill);
                float angle = (float) ((fStartAngle + fEndAngle / 2) * Math.PI / 180);
                float stopX = (float) (startX + (radius/2) * Math.cos(angle));
                float stopY = (float) (startY + (radius/2) * Math.sin(angle));
    
    
                // if the part of pie was selected then draw a border
                if (iSelectedIndex == i) {
                    canvas.drawArc(r, fStartAngle, fEndAngle, true, paintPieBorder);
                     canvas.drawLine(startX, startY, stopX, stopY, paintPieFill);
                    canvas.restore();
                }
                fStartAngle = fStartAngle + fEndAngle;
            }
    
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            // get screen size
            iDisplayWidth = MeasureSpec.getSize(widthMeasureSpec);
            iDisplayHeight = MeasureSpec.getSize(heightMeasureSpec);
    
            if (iDisplayWidth > iDisplayHeight) {
                iDisplayWidth = iDisplayHeight;
            }
    
            /*
             * determine the rectangle size
             */
            iCenterWidth = iDisplayWidth / 2;
            int iR = iCenterWidth - iMargin;
            if (r == null) {
                r = new RectF(iCenterWidth - iR, // top
                        iCenterWidth - iR, // left
                        iCenterWidth + iR, // right
                        iCenterWidth + iR); // bottom
            }
            if (centerCircle == null) {
                // centerCircle=new RectF(left, top, right, bottom);
    
            }
            setMeasuredDimension(iDisplayWidth, iDisplayWidth);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            // get degree of the touch point
            double dx = Math.atan2(event.getY() - iCenterWidth, event.getX()
                    - iCenterWidth);
            float fDegree = (float) (dx / (2 * Math.PI) * DEGREE_360);
            fDegree = (fDegree + DEGREE_360) % DEGREE_360;
    
            // get the percent of the selected degree
            float fSelectedPercent = fDegree * 100 / DEGREE_360;
    
            // check which pie was selected
            float fTotalPercent = 0;
            for (int i = 0; i < iDataSize; i++) {
                fTotalPercent += alPercentage.get(i);
                if (fTotalPercent > fSelectedPercent) {
                    iSelectedIndex = i;
                    break;
                }
            }
            if (onSelectedListener != null) {
                onSelectedListener.onSelected(iSelectedIndex);
            }
            invalidate();
            return super.onTouchEvent(event);
        }
    
        private void fnGetDisplayMetrics(Context cxt) {
            final DisplayMetrics dm = cxt.getResources().getDisplayMetrics();
            fDensity = dm.density;
        }
    
        private float fnGetRealPxFromDp(float fDp) {
            return (fDensity != 1.0f) ? fDensity * fDp : fDp;
        }
    
        public void setAdapter(ArrayList<Float> alPercentage) throws Exception {
            this.alPercentage = alPercentage;
            iDataSize = alPercentage.size();
            float fSum = 0;
            for (int i = 0; i < iDataSize; i++) {
                fSum += alPercentage.get(i);
            }
            if (fSum != 100) {
                Log.e(TAG, ERROR_NOT_EQUAL_TO_100);
                iDataSize = 0;
                throw new Exception(ERROR_NOT_EQUAL_TO_100);
            }
    
        }
    

    在您的布局中:

    <com.example.piecharts.PieChart
            android:id="@+id/pieChart"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
        </com.example.piecharts.PieChart>
    

    【讨论】:

      【解决方案4】:

      这个问题已经很老了,但我想我会写一个一般性的答案。在这里,我假设您想在画布中间绘制饼图,并且您的起始角和渗透角在一个数组中。

      x = canvas.getWidth/2 //Horizontal center of canvas view
      y = canvas.getHeight/2 //Vertical center of canvas view
      canvas.rotate(fStartAngle[i]+ fSweepAngle[i]/2, x ,y ); //Rotates canvas to a line in the middle 
      //of start and end of arc
      canvas.translate(50f,0);//Moves the text a little out of the center of the circle (50f is arbitrary)
      paintText.setStyle(Paint.Style.FILL);
      canvas.drawText(rotatedtext, x, y, paintText);
      //Undo the translations and rotations so that next arc can be drawn normally
      canvas.translate(-50f,0); 
      canvas.rotate(-(temp+ value_degree[i]/2), x ,y );
      

      【讨论】:

        【解决方案5】:

        聚会有点晚了,但我必须弄清楚这个,它比我发现的要简单一些。您已经有了文本的 x 和 y,使用它们来旋转画布

        canvas.rotate(yourDegrees, x, y)
        canvas.drawText(yourText, x, y, yourPaint)
        canvas.rotate(-yourDegrees, x, y)
        

        负号否定第一次旋转。你可以把它换成相反的方向旋转。

        您可以循环执行此操作,但每次坐标更改时都必须执行旋转循环。

        【讨论】:

          猜你喜欢
          • 2014-01-18
          • 2013-04-06
          • 1970-01-01
          • 2012-11-27
          • 2012-08-25
          • 2022-10-23
          • 1970-01-01
          • 2014-12-29
          • 1970-01-01
          相关资源
          最近更新 更多