Android自定义控件

Android自定义控件

1.组合控件。

几个现有控件,组合起来,达到使用的目的。初始化时,新布局填充到控件上。

组合控件定义一个密码输入框,右侧可以点击图标,来切换密码是显示或隐藏。

布局文件:由editText和img组成。

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">
           
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"/>
           
android:id="@+id/gy_rl_edittext_right"
       
android:layout_width="48dp"
       
android:layout_height="match_parent"
       
android:layout_alignParentRight="true"
       
android:gravity="center"
       
>
                   
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

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();
    }
}

代码中使用:当做正常控件来使用。

android:layout_width="match_parent"
    android:layout_height="60dp">

 

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, String>> urls;

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


    public void setData(List, 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"?>
xmlns:android="http://schemas.android.com/apk/res/android" >
    android:duration="1000"
        android:fromYDelta="100%p"
        android:toYDelta="0%p" />

verrical_out

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

 

3.继承View或者ViewGroup

3.1继承View

Values/attrs.xml

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


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

    name="CustomTxtView">
        name="text"/>
        name="textSize"/>
   


 

 

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"

 

android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    customtext:text="12378"
    customtext:textSize="16sp"
    />

 

你可能感兴趣的