Android 사용자 정의 View 에서 Spannable 을 사용 하 는 실례 상세 설명

Android 에서 Spannable 을 사용 하면 TextView 부 텍스트 를 표시 할 수 있다 는 것 을 잘 알 고 있 습 니 다.그러나 사용자 정의 컨트롤 에서 Spannable 을 사용 하여 다양한 스타일 의 문 자 를 그 리 는 방법 은 무엇 입 니까?

예 를 들 어 이런 효 과 는 제목 의 61은 굵 은 체 이 고 는 일반적인 글씨체 이 며61보다 작다.
첫 번 째 반응 은SpannableString.setSpan()설정RelativeSizeSpan을 사용 한 다음 에onDraw()에서 그 릴 수 있 습 니 다.사실은 이렇게 실현 하 는 것 은 효과 가 없습니다.onDraw()에서SpannableString중의 내용 만 얻 을 수 있 고 받 을 수 없 기 때 문 입 니 다Span.
그러면 어떻게 사용자 정의 View 에서 Spannable 을 사용 합 니까?정 답 은 시스템 이 제공 하 는Layout유형 이다.

/**
 * A base class that manages text layout in visual elements on
 * the screen.
 * <p>For text that will be edited, use a {@link DynamicLayout},
 * which will be updated as the text changes.
 * For text that will not change, use a {@link StaticLayout}.
 */
public abstract class Layout {
 
}


이 를 통 해 알 수 있 듯 이Layout는 추상 적 인 유형 으로 세 가지 유형 이 있 으 며 자동 으로 줄 을 바 꾸 는 디 스 플레이 효 과 를 실현 할 수 있다.
  • BoringLayout
  • DynamicLayout
  • StaticLayout
  • 구현 코드
    1.사용자 정의 속성 정의
    
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
     <declare-styleable name="ArcProgressView">
      <attr name="arcBackgroundColor" format="color" />
      <attr name="arcProgressColor" format="color" />
      <attr name="arcSubTitleColor" format="color" />
      <attr name="arcStrokeWidth" format="dimension" />
      <attr name="arcTitleTextSize" format="dimension" />
      <attr name="arcSubTitleTextSize" format="dimension" />
      <attr name="arcProgress" format="float" />
      <attr name="arcTitleNumber" format="integer" />
     </declare-styleable>
    </resources>
    2.View 계승,onDraw()에서 그리 기
    
    public class ArcProgressView extends View {
     private int arcBackgroundColor; //       
     private int arcProgressColor;  //       
     private int arcSubTitleColor;  //      
     private float arcStrokeWidth;  //       
     private float arcTitleTextSize; //       
     private float arcSubTitleTextSize; //        
     private float arcProgress; //   
     private int arcTitleNumber; //  
     private Paint paint;
     private float centerX;
     private float centerY;
     private float radius; //   
     private RectF rectF;
     private int startAngle = 135;
     private int sweepAngle = 270;
     private String subTitle = "1  ";
     private SpannableString spannableString;
     private TextPaint textPaint;
     private RelativeSizeSpan relativeSizeSpan;
     private DynamicLayout dynamicLayout;
     private String text = "11 ";
     private StyleSpan styleSpan;
     private float curProgress; //     
     private int curNumber;
     public ArcProgressView(Context context) {
      this(context, null);
     }
     public ArcProgressView(Context context, @Nullable AttributeSet attrs) {
      this(context, attrs, 0);
     }
     public ArcProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      readAttrs(context, attrs);
      init(context);
     }
     private void readAttrs(Context context, AttributeSet attributeSet) {
      TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.ArcProgressView);
      arcBackgroundColor = typedArray.getColor(R.styleable.ArcProgressView_arcBackgroundColor, 0x1c979797);
      arcProgressColor = typedArray.getColor(R.styleable.ArcProgressView_arcProgressColor, 0xff3372FF);
      arcSubTitleColor = typedArray.getColor(R.styleable.ArcProgressView_arcSubTitleColor, 0x66000000);
      arcStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.ArcProgressView_arcStrokeWidth, dp2px(5));
      arcTitleTextSize = typedArray.getDimensionPixelSize(R.styleable.ArcProgressView_arcTitleTextSize, dp2px(30));
      arcSubTitleTextSize = typedArray.getDimensionPixelSize(R.styleable.ArcProgressView_arcSubTitleTextSize, dp2px(14));
      arcProgress = typedArray.getFloat(R.styleable.ArcProgressView_arcProgress, 1.0f);
      arcTitleNumber = typedArray.getInt(R.styleable.ArcProgressView_arcTitleNumber, 100);
      typedArray.recycle();
     }
     private void init(Context context) {
      paint = new Paint(Paint.ANTI_ALIAS_FLAG);
      paint.setStrokeCap(Paint.Cap.ROUND);
      relativeSizeSpan = new RelativeSizeSpan(0.6f);
      styleSpan = new StyleSpan(android.graphics.Typeface.BOLD);
      textPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
      textPaint.setColor(arcProgressColor);
    //  textPaint.setTextAlign(Paint.Align.CENTER); //              
      textPaint.setTextSize(sp2px(22));
     }
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
      super.onSizeChanged(w, h, oldw, oldh);
      centerX = w / 2f;
      centerY = h / 2f;
      radius = (Math.min(w, h) - arcStrokeWidth) / 2f;
      rectF = new RectF(-radius, -radius, radius, radius);
     }
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      int width = getMeasuredSize(widthMeasureSpec, dp2px(100));
      int height = getMeasuredSize(heightMeasureSpec, dp2px(100));
      setMeasuredDimension(width, height);
     }
     @Override
     protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);
      //        
      drawArc(canvas);
      //      title
      drawTitleText(canvas);
      //        
      drawSubTitle(canvas);
     }
     @Override
     protected void onAttachedToWindow() {
      super.onAttachedToWindow();
      startAnimation();
     }
     private void startAnimation() {
      ValueAnimator progressAnimator = ValueAnimator.ofFloat(0f, arcProgress);
      ValueAnimator numberAnimator = ValueAnimator.ofInt(0, arcTitleNumber);
      progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
       @Override
       public void onAnimationUpdate(ValueAnimator animation) {
        curProgress = (float) animation.getAnimatedValue();
        invalidate();
       }
      });
      numberAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
       @Override
       public void onAnimationUpdate(ValueAnimator animation) {
        curNumber = (int) animation.getAnimatedValue();
        text = curNumber + " ";
       }
      });
      AnimatorSet animatorSet = new AnimatorSet();
      animatorSet.playTogether(progressAnimator, numberAnimator);
      animatorSet.setDuration(700);
      animatorSet.setInterpolator(new LinearInterpolator());
      animatorSet.start();
     }
     private void drawSubTitle(Canvas canvas) {
      canvas.save();
      canvas.translate(centerX, centerY);
      paint.setTextSize(arcSubTitleTextSize);
      paint.setTextAlign(Paint.Align.CENTER);
      paint.setColor(arcSubTitleColor);
      paint.setStyle(Paint.Style.FILL);
      paint.setStrokeWidth(0);
      canvas.drawText(subTitle, 0, 60, paint);
      canvas.restore();
     }
     private void drawArc(Canvas canvas) {
      canvas.save();
      canvas.translate(centerX, centerY);
      paint.setColor(arcBackgroundColor);
      paint.setStrokeWidth(arcStrokeWidth);
      paint.setStyle(Paint.Style.STROKE);
      canvas.drawArc(rectF, startAngle, sweepAngle, false, paint);
      paint.setColor(arcProgressColor);
      canvas.drawArc(rectF, startAngle, sweepAngle * curProgress, false, paint);
      canvas.restore();
     }
     private void drawTitleText(Canvas canvas) {
      canvas.save();
      textPaint.setTextSize(arcTitleTextSize);
      float textWidth = textPaint.measureText(text); //     
      float textHeight = -textPaint.ascent() + textPaint.descent(); //     
      //    StaticLayout      ,    Canvas (0,0)   ,          ,      translate     。
      canvas.translate(centerX - textWidth * 2 / 5f, centerY - textHeight * 2 / 3f);
      spannableString = SpannableString.valueOf(text);
      spannableString.setSpan(styleSpan, 0, text.length() - 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
      spannableString.setSpan(relativeSizeSpan, text.length() - 1, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
      dynamicLayout = new DynamicLayout(spannableString, textPaint, getWidth(), Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
      dynamicLayout.draw(canvas);
      canvas.restore();
     }
     /**
      *       ,    
      *
      * @param percent
      */
     public void setArcProgress(float percent) {
      this.curProgress = percent;
      invalidate();
     }
     private int getMeasuredSize(int measureSpec, int defvalue) {
      int mode = MeasureSpec.getMode(measureSpec);
      int size = MeasureSpec.getSize(measureSpec);
      if (mode == MeasureSpec.EXACTLY) {
       return size;
      }
      return Math.min(size, defvalue);
     }
     private int dp2px(int dp) {
      return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
     }
     private int sp2px(int sp) {
      return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
     }
    }
    3.레이아웃 에서 참조
    
    <com.xing.bottomsheetsample.ArcProgressView
      android:layout_width="match_parent"
      android:layout_height="100dp"
      android:layout_marginTop="20dp"
      app:arcProgress="0.6"
      app:arcSubTitleTextSize="14sp"
      app:arcTitleNumber="61"
      app:arcTitleTextSize="28sp" />
    총결산
    안 드 로 이 드 사용자 정의 뷰 에서 Spannable 을 사용 하 는 것 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 안 드 로 이 드 가 Spannable 을 사용 하 는 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

    좋은 웹페이지 즐겨찾기