Android自定義控件

Android自定義控件

1.組合控件。

幾個現有控件,組合起來,達到使用的目的。初始化時,新佈局填充到控件上。

組合控件定義一個密碼輸入框,右側可以點擊圖標,來切換密碼是顯示或隱藏。

佈局文件:由editText和img組成。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   
xmlns:tools="http://schemas.android.com/tools"
   
android:layout_width="match_parent"
   
android:layout_height="60dp"
   
tools:context="com.example.yijian.testanination.MainActivity">
    <EditText
       
android:id="@+id/et_password"
       
android:hint="請輸入密碼"
       
android:singleLine="true"
       
android:maxLength="50"
       
android:layout_width="match_parent"
       
android:layout_height="match_parent"
       
android:background="@null"/>
    <RelativeLayout
       
android:id="@+id/gy_rl_edittext_right"
       
android:layout_width="48dp"
       
android:layout_height="match_parent"
       
android:layout_alignParentRight="true"
       
android:gravity="center"
       
>
        <ImageView
           
android:id="@+id/gy_img_edittext_right"
           
android:background="@drawable/gy_password_eye_off"
           
android:clickable="false"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content" />
    </RelativeLayout>
</RelativeLayout>

定義控件類繼承RelativeLayout

public class MyTextView extends RelativeLayout {
    private RelativeLayout layout = null;
    private EditText mEtPassword;
    private RelativeLayout mLlRightPic;

    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    public MyTextView(Context context) {
        super(context);
        init(context);
    }
    /**
     * 初始化
     * @param context
     */
    private void init(Context context) {
        if (layout == null)
            layout = (RelativeLayout) ((LayoutInflater) (context.getSystemService(Context.LAYOUT_INFLATER_SERVICE))).
                    inflate(R.layout.my_textview,this);
        mEtPassword = (EditText) layout.findViewById(R.id.et_password);
        mLlRightPic = (RelativeLayout) layout.findViewById(R.id.gy_rl_edittext_right);

        mLlRightPic.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //右側圖標點擊時,切換 顯示密碼和隱藏密碼的設置
            }
        });
    }

    public String getText(){
        //返回用戶輸入的密碼
        return mEtPassword.getEditableText().toString();
    }
}

代碼中使用:當做正常控件來使用。

<com.example.yijian.testanination.MyTextView
    android:layout_width="match_parent"
    android:layout_height="60dp">
</com.example.yijian.testanination.MyTextView>

 

2.繼承現有控件,實現所需功能。

有些情況下直接繼承現有控件,也十分方便。

這種情況要求,對要繼承的類較爲熟悉。

比如防止Button控件連續點擊,可以重寫button

/**
 * Created by gj on 2016/5/11.
 * 統一按鈕
 */
public class GyButton extends Button {
    public GyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    public GyButton(Context context) {
        super(context);
        init(context);
    }
//button_selecter
    private void init(Context context) {
        setBackgroundDrawable(getResources().getDrawable(R.drawable.button));
        setTextSize(16);
        setTextColor(context.getResources().getColor(R.color.textcolor_on_up_widget));
    }
    @Override
    public boolean performClick() {
        if(DataTimeUtil.buttonIsDoubleClick()){
            return false;
        }else{
            return super.performClick();
        }
    }
}

 

ViewPager添加小圓點指示器

onDraw中去繪製圓點。getAdapter能拿到適配器。getCount可以拿到元素的數量。getCurrentItem當前索引。

這樣就可以自動的設置指示器。

/**
 * Created by gj on 2017/2/8.
 */
public class IndicatorViewPager extends ViewPager{

    Context context;
    Paint paint;
    List<Map<String, String>> urls;

    public IndicatorViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        paint = new Paint();
    }


    public void setData(List<Map<String, String>> data) {
        urls.clear();
        for (int i = 0; i < data.size(); i++) {
            urls.add(data.get(i));
        }
        if(urls.size()>0){
            this.setVisibility(View.VISIBLE);
        }else{
            this.setVisibility(View.GONE);
        }
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        drawCycle(canvas);
    }

    private void drawCycle(Canvas canvas) {
        canvas.save();
        canvas.translate(getScrollX(), getScrollY());
        int count = 0;
        if (this.getAdapter() != null) {
            count = this.getAdapter().getCount();
        }
        int select = getCurrentItem();
        float density = getContext().getResources().getDisplayMetrics().density;
        int itemWidth = (int) (11 * density);
        int itemHeight = itemWidth / 2;
        int x = (getWidth() - count * itemWidth)/2;
        int y = getHeight() - itemWidth;
        int minItemHeight = (int) ((float) itemHeight * 0.8F);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        for (int i = 0; i < count; i++) {
            if (select == i) {
                paint.setColor(0xFF666666);
                canvas.drawCircle((x + itemWidth * i + itemWidth / 2)+350, y, minItemHeight, paint);
            } else {
                paint.setColor(0xFFe6e6e6);
                canvas.drawCircle((x + itemWidth * i + itemWidth / 2)+350, y, minItemHeight, paint);
            }
        }
        canvas.restore();
    }

}

 

實現文字的垂直滾動效果。

繼承TextSwitcher(文字轉換器)。即可正常設置文字。

/**
 * 自動垂直滾動的TextView
 */
public class VerticalScrollTextView extends TextSwitcher implements ViewSwitcher.ViewFactory {
    private Context mContext;
    //mInUp,mOutUp分別構成向下翻頁的進出動畫
    private Animation mInAnimation;
    private Animation mOutAnimation;
    public VerticalScrollTextView(Context context) {
        this(context, null);
    }
    public VerticalScrollTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }
    private void init() {
        //設置TextView的產生,會調用ViewFactory.makeView()
        setFactory(this);
        //設置出入動畫
        mInAnimation = AnimationUtils.loadAnimation(mContext, R.anim.vertical_in);
        mOutAnimation = AnimationUtils.loadAnimation(mContext, R.anim.vertical_out);
        setInAnimation(mInAnimation);
        setOutAnimation(mOutAnimation);
    }
    //這裏返回的TextView,就是我們看到的View,可以設置自己想要的效果
    @Override
    public View makeView() {
        TextView textView = new TextView(mContext);
        textView.setTextSize(36);
//        textView.setSingleLine(true);
//        textView.setGravity(Gravity.CENTER_VERTICAL);
        return textView;
    }
}

動畫vertical_in

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="1000"
        android:fromYDelta="100%p"
        android:toYDelta="0%p" />
</set>

verrical_out

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="1000"
        android:fromYDelta="0%p"
        android:toYDelta="-100%p" />
</set>

 

3.繼承View或者ViewGroup

3.1繼承View

Values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr
name="text"format="string" />
    <attr
name="textSize"format="dimension" />

    <declare-styleable
name="CustomTxtView">
        <attr
name="text"/>
        <attr
name="textSize"/>
    </declare-styleable>

</resources> 

 

CustomerView繼承成View類

構造方法走三個參數的。

public CustomerView(Context context) {
    this(context,null);
}

public CustomerView(Context context, AttributeSet attrs) {
    this(context, attrs,0);
}

 

public CustomerView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    /**
     * 獲得我們所定義的自定義樣式屬性
     */
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTxtView, defStyleAttr, 0);
    int n = a.getIndexCount();

    for (int i = 0; i < n; i++)
    {
        int attr = a.getIndex(i);
        switch (attr)
        {
            case R.styleable.CustomTxtView_text:
                this.text =  a.getString(attr);
                break;
            case R.styleable.CustomTxtView_textSize:
                // 默認設置爲16sp,TypeValue也可以把sp轉化爲px
                mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                break;
        }
    }
    mPaint = new Paint();
    mPaint.setTextSize(mTitleTextSize);

    mBound = new Rect();
    mPaint.getTextBounds(text, 0, text.length(), mBound);

}

 

實現onDraw、onMeasure

@Override
    protected void onDraw(Canvas canvas)
    {
        mPaint.setColor(Color.YELLOW);
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);

        mPaint.setColor(Color.BLACK);
        canvas.drawText(text, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
    }
//    先了解MeasureSpec的specMode,一共三種類型:
//    EXACTLY:一般是設置了明確的值或者是MATCH_PARENT
//    AT_MOST:表示子佈局限制在一個最大值內,一般爲WARP_CONTENT
//    UNSPECIFIED:表示子佈局想要多大就多大,很少使用
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int width;
        int height ;
        if (widthMode == MeasureSpec.EXACTLY)
        {
            width = widthSize;
        } else
        {
            mPaint.setTextSize(mTitleTextSize);
            mPaint.getTextBounds(text, 0, text.length(), mBound);
            float textWidth = mBound.width();
            int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
            width = desired;
        }

        if (heightMode == MeasureSpec.EXACTLY)
        {
            height = heightSize;
        } else
        {
            mPaint.setTextSize(mTitleTextSize);
            mPaint.getTextBounds(text, 0, text.length(), mBound);
            float textHeight = mBound.height();
            int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
            height = desired;
        }
        setMeasuredDimension(width, height);
    }

 

在佈局中使用(需要添加約束)

xmlns:customtext="http://schemas.android.com/apk/res-auto"

 

<com.example.yijian.testanination.widget.CustomerView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    customtext:text="12378"
    customtext:textSize="16sp"
    />

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章