2013-08-26 2 views
2

SeekBar에 대한 맞춤 스타일이 있습니다. 라벨을 추가하고 싶습니다.맞춤 검색 바에있는 Android 라벨

<?xml version="1.0" encoding="utf-8"?> 
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > 
    <item 
     android:id="@android:id/background" 
     android:drawable="@drawable/seekbar_background"/> 
</layer-list> 

seekbar_background 9 패치는 다음과 같습니다 : 나는 바의 각 끝을 통해 라벨을하고 싶은 enter image description here

SeekBar처럼 보이는 진행 그릴 수 있습니다. 바람직하게는, 라벨은 각면의 벌브 상에 텍스트 중심을 가질 것이다. 의 끝점을 중심으로 TextView을 가운데에 배치 할 수 있어야하지만 한보기의 중심을 다른보기의 가장자리와 맞출 수있는 방법을 찾지 못했습니다.

SeekBar API를 사용하거나 레이아웃 정렬을 영리하게 사용하여 방법을 사용할 수 있습니까?

+0

당신은 확장하는 것을 시도했다 필요한 효과를 얻으려면 SeekBar를 사용 하시겠습니까? – sandrstar

+0

@sandrstar 확장 방법을 어떻게 제안 하시겠습니까? 라벨을 제대로 정렬하는 방법에 대해 어떻게 생각하는지 모르겠습니다. – karl

+0

onDraw에서 텍스트의 그림을 추가하기 만하면됩니다 (거기에 모든 위치 정보가 있습니다). 양 끝 위에 두 개의 레이블 (예 : '시작'및 '끝')을 표시 하시겠습니까? – sandrstar

답변

5

사용자 정의 View/ViewGroup의 생성이 트릭을 수행 할 수 있다고 생각합니다. 아래의 예는 내가 수행 할 수 있다고 믿는 몇 가지 예입니다.

main.xml에 : 정의와

<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:custom="http://schemas.android.com/apk/res/com.example.TestApp" 
    android:layout_height="match_parent" 
    android:layout_width="match_parent" 
    android:id="@+id/root"> 

    <com.example.TestApp.LabelledSeekBar 
     android:layout_width="300dp" 
     android:layout_height="wrap_content" 
     android:layout_centerInParent="true" 
     custom:labelLeft="@string/left_label" 
     custom:labelRight="@string/right_label" 
     custom:labelPaddingBottom="@dimen/label_padding_bottom" 
     custom:labelCenterSidePadding="@dimen/label_padding_side" 
     android:textSize="@dimen/label_text_size" 
     android:textColor="@android:color/white" 
     android:textStyle="italic" 
     android:progressDrawable="@drawable/seek_progress" /> 

</RelativeLayout> 

attrs.xml이 속성 : 사용자 정의보기/뷰 그룹의

<resources> 
    <declare-styleable name="LabelledSeekBar"> 
     <attr name="labelLeft" format="string"/> 
     <attr name="labelRight" format="string"/> 
     <attr name="labelPaddingBottom" format="dimension"/> 
     <!-- This is bulb center padding --> 
     <attr name="labelCenterSidePadding" format="dimension"/> 
    </declare-styleable> 
</resources> 

핵심 아이디어는 단지 텍스트의 적절한 배치를 제공하고 적합한 측정을 할 수있다 보기. 사용자 정의 뷰 그룹 자체 (아래 코드의 많은)입니다 :

public class LabelledSeekBar extends ViewGroup { 

    /** SeekBar itself */ 
    private final SeekBar mSeekBar; 
    /** Label for left end */ 
    private String mLeftLabel = null; 
    /** Label for right end */ 
    private String mRightLabel = null; 
    /** Bottom paddings for labels */ 
    private static final int DEFAULT_LABEL_PADDING_BOTTOM = 10; // px 
    private int mLabelPaddingBottom = DEFAULT_LABEL_PADDING_BOTTOM; 
    /** Center of 'bulbs' to draw labels above centered */ 
    private static final int DEFAULT_LABEL_PADDING_SIDE = 10; // px 
    private int mLabelCenterPadding = DEFAULT_LABEL_PADDING_SIDE; 
    /** Here goes labels attributes, they are similar to TextViews ones */ 
    private static final int DEFAULT_TEXT_SIZE = 10; // px 
    private static final int DEFAULT_TEXT_COLOR = Color.BLACK; // px 
    private static final Typeface DEFAULT_TEXT_STYLE = Typeface.DEFAULT; // px 
    private int mTextSize = DEFAULT_TEXT_SIZE; 
    private int mTextColor = DEFAULT_TEXT_COLOR; 
    private Typeface mTextStyle = DEFAULT_TEXT_STYLE; 
    /** Bounds for labels rects */ 
    private Rect mLeftTextBound = null; 
    private Rect mRightTextBound = null; 
    /** Rect for SeekBar */ 
    private Rect mSeekBarRect = null; 
    /** Default height for SeekBar */ 
    private int mDefaultSeekBarHeight = 0; 
    /** Paint for text */ 
    private Paint mTextPaint = null; 
    /** Flag to draw or not the labels */ 
    private boolean mDrawLabels = false; 

    /** 
    * Constructor 
    */ 
    public LabelledSeekBar(final Context context) { 
     super(context); 
     mSeekBar = new SeekBar(context); 
     init(null); 
    } 

    /** 
    * Constructor 
    */ 
    public LabelledSeekBar(final Context context, final AttributeSet attrs) { 
     super(context, attrs); 
     mSeekBar = new SeekBar(context, attrs); 
     init(attrs); 
    } 

    /** 
    * Constructor 
    */ 
    public LabelledSeekBar(final Context context, final AttributeSet attrs, final int defStyle) { 
     super(context, attrs, defStyle); 
     mSeekBar = new SeekBar(context, attrs, defStyle); 
     init(attrs); 
    } 

    @Override 
    protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) { 
     mSeekBar.layout(mSeekBarRect.left, mSeekBarRect.top, mSeekBarRect.right, mSeekBarRect.bottom); 
    } 

    /** 
    * Initializes Seek bar extended attributes from xml 
    * 
    * @param attributeSet {@link AttributeSet} 
    */ 
    private void init(final AttributeSet attributeSet) { 
     final TypedArray attrsArray = getContext().obtainStyledAttributes(attributeSet, R.styleable.LabelledSeekBar, 0, 0); 

     mDefaultSeekBarHeight = getResources().getDimensionPixelSize(R.dimen.default_seekbar_height); 

     mLeftLabel = attrsArray.getString(R.styleable.LabelledSeekBar_labelLeft); 
     mRightLabel = attrsArray.getString(R.styleable.LabelledSeekBar_labelRight); 
     mLabelPaddingBottom = attrsArray.getDimensionPixelOffset(R.styleable.LabelledSeekBar_labelPaddingBottom, DEFAULT_LABEL_PADDING_BOTTOM); 
     mLabelCenterPadding = attrsArray.getDimensionPixelOffset(R.styleable.LabelledSeekBar_labelCenterSidePadding, DEFAULT_LABEL_PADDING_SIDE); 

     // Now get needed Text attributes 
     final int textSizeResource = attributeSet.getAttributeResourceValue("http://schemas.android.com/apk/res/android", "textSize", 0); 

     if (0 != textSizeResource) { 
      mTextSize = getResources().getDimensionPixelSize(textSizeResource); 
     } 

     final int textColorResource = attributeSet.getAttributeResourceValue("http://schemas.android.com/apk/res/android", "textColor", 0); 

     if (0 != textColorResource) { 
      mTextColor = getResources().getColor(textColorResource); 
     } 

     final int typeface = attributeSet.getAttributeIntValue("http://schemas.android.com/apk/res/android", "textStyle", 0); 

     switch (typeface) { 
      // normale 
      case 0: 
       mTextStyle = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL); 
       break; 
      // bold 
      case 1: 
       mTextStyle = Typeface.create(Typeface.DEFAULT, Typeface.BOLD); 
       break; 
      // italic 
      case 2: 
       mTextStyle = Typeface.create(Typeface.DEFAULT, Typeface.ITALIC); 
       break; 
      // bold | italic 
      case 3: 
       mTextStyle = Typeface.create(Typeface.DEFAULT, Typeface.BOLD_ITALIC); 
       break; 
     } 

     mTextPaint = new TextPaint(); 
     mTextPaint.setColor(mTextColor); 
     mTextPaint.setTextSize(mTextSize); 
     mTextPaint.setTypeface(mTextStyle); 
     mTextPaint.setTextAlign(Paint.Align.LEFT); 
     mTextPaint.setStyle(Paint.Style.FILL); 

     addView(mSeekBar); 
    } 

    /** 
    * Setters for labels 
    * 
    * @param leftLabel {@link String} 
    * @param rightLabel {@link String} 
    */ 
    public void setLabels(final String leftLabel, final String rightLabel) { 
     mLeftLabel = leftLabel; 
     mRightLabel = rightLabel; 

     requestLayout(); 
    } 

    @Override 
    protected synchronized void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { 
     // measure labels height - this logic is not very strict and can be changed 
     mLeftTextBound = new Rect(); 
     mTextPaint.getTextBounds(mLeftLabel, 0, mLeftLabel.length(), mLeftTextBound); 
     mRightTextBound = new Rect(); 
     mTextPaint.getTextBounds(mRightLabel, 0, mRightLabel.length(), mRightTextBound); 

     final int labelHeight = Math.max(mLeftTextBound.height(), mRightTextBound.height()); 
     final int desiredMinHeight = labelHeight + mLabelPaddingBottom; 
     final int desiredMinWidth = mLeftTextBound.width() + mRightTextBound.width(); 
     final int widthSize = MeasureSpec.getSize(widthMeasureSpec); 
     final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
     final int heightSize = MeasureSpec.getSize(heightMeasureSpec); 
     final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
     int measuredWidth = 0; 
     int measuredHeight = 0; 

     mSeekBarRect = new Rect(); 

     // Calculate width 
     switch (widthMode) { 
      case MeasureSpec.EXACTLY: 
      case MeasureSpec.AT_MOST: 
       if (widthSize < desiredMinWidth) { 
        mDrawLabels = false; 
       } else { 
        mDrawLabels = true; 
        mSeekBarRect.set(mLeftTextBound.width()/2 - mLabelCenterPadding, desiredMinHeight, 
          widthSize - mRightTextBound.width()/2 + mLabelCenterPadding, heightSize); 
       } 
       measuredWidth = widthSize; 
       break; 

      case MeasureSpec.UNSPECIFIED: 
       mDrawLabels = true; 
       measuredWidth = desiredMinWidth + mLabelCenterPadding * 4; 
       mSeekBarRect.set(mLeftTextBound.width()/2 - mLabelCenterPadding, desiredMinHeight, 
         widthSize - mRightTextBound.width()/2 + mLabelCenterPadding, heightSize); 
       break; 
     } 

     if (mDrawLabels) { 
      // Calculate height 
      switch (heightMode) { 
       case MeasureSpec.EXACTLY: 
       case MeasureSpec.AT_MOST: 
        if (heightSize < desiredMinHeight) { 
         mDrawLabels = false; 
        } else { 
         mDrawLabels = true; 
         mSeekBarRect.top = desiredMinHeight; 
         mSeekBarRect.bottom = heightSize > mDefaultSeekBarHeight ? (desiredMinHeight + mDefaultSeekBarHeight) : heightSize; 
        } 
        measuredHeight = (heightSize > (desiredMinHeight + mDefaultSeekBarHeight)) ? (desiredMinHeight + mDefaultSeekBarHeight) : heightSize; 
        break; 

       case MeasureSpec.UNSPECIFIED: 
        mDrawLabels = true; 
        measuredHeight = desiredMinHeight + mDefaultSeekBarHeight; 
        mSeekBarRect.top = desiredMinHeight; 
        mSeekBarRect.bottom = measuredHeight; 
        break; 
      } 
     } else { 
      switch (heightMode) { 
       case MeasureSpec.EXACTLY: 
       case MeasureSpec.AT_MOST: 
        measuredHeight = heightSize; 
        break; 

       case MeasureSpec.UNSPECIFIED: 
        measuredHeight = mDefaultSeekBarHeight; 
        break; 
      } 
     } 

     if (!mDrawLabels) { 
      // define SeekBar rect 
      mSeekBarRect.set(0, 0, measuredWidth, measuredHeight); 
     } 

     mSeekBar.measure(MeasureSpec.makeMeasureSpec(mSeekBarRect.width(), MeasureSpec.EXACTLY), 
       MeasureSpec.makeMeasureSpec(mSeekBarRect.height(), MeasureSpec.EXACTLY)); 

     setMeasuredDimension(measuredWidth, measuredHeight); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    protected void dispatchDraw(final Canvas canvas) { 
     if (mDrawLabels) { 
      final int height = Math.max(mLeftTextBound.height(), mRightTextBound.height()); 

      canvas.drawText(mLeftLabel, 0, height, mTextPaint); 
      canvas.drawText(mRightLabel, getMeasuredWidth() - mRightTextBound.width(), height, mTextPaint); 
     } 

     super.dispatchDraw(canvas); 
    } 

    /** 
    * Any layout manager that doesn't scroll will want this. 
    */ 
    @Override 
    public boolean shouldDelayChildPressedState() { 
     return false; 
    } 
} 

결과는 다음과 같습니다 (통지 다른 텍스트,하지만 모두 거의 전구 위에 집중되어) :

example of view

+0

시간을 내 주셔서 감사합니다. 나는 둘 다 짧기 때문에 내 레이블에 약간의 패딩을 추가하는 것으로 끝났다. 그리고 그것은 충분히 가깝게 나온다. 확실히 이걸주고 움직이는 방법을 보도록하겠습니다. – karl