Android自定义View入门级

来源:互联网 发布:淘宝药店 提交需求 编辑:程序博客网 时间:2024/05/18 03:08

Android入门级的自定义View,比较基础,例子也都是找的大神的博客看看敲敲的。直接上代码,代码中有详细注释。

一、Android自定义View

总结来说,自定义控件的实现有三种方式,分别是:自绘控件、组合控件和继承控件。
三个比较重要的方法:onMeasure(),onLayout(),onDraw()

二、自定义View自绘控件

(继承View的点击获取随机数显示)
博客:http://blog.csdn.net/lmj623565791/article/details/24252901/
1、在res/values/目录下新建一个attrs.xml,在里面声明属性和样式

<resources>    //自定义属性    <declare-styleable name="custom_view">        <attr name="text_color" format="color" />        <attr name="text_text" format="string" />        <attr name="text_size" format="dimension" />    </declare-styleable></resources>

2、继承View类,在构造方法中,获取我们的样式

public class MyCustomView extends View {    private String mTextString;    private int mTextColor;    private float mTextSize;    //图形和画笔    private Rect mRect;    private Paint mPaint;    public MyCustomView(Context context) {        this(context, null);    }    public MyCustomView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //和XML中的属性建立连接        TypedArray _typeArray = context.obtainStyledAttributes(attrs, R.styleable.custom_view, defStyleAttr, 0);        mTextString = _typeArray.getString(R.styleable.custom_view_text_text);        mTextColor = _typeArray.getColor(R.styleable.custom_view_text_color, 0);        mTextSize = _typeArray.getDimension(R.styleable.custom_view_text_size, (float) 15);        //使用recycle()方法,使得可以实时获取属性值        _typeArray.recycle();        //画一个矩形        mPaint = new Paint();        mPaint.setTextSize(mTextSize);        mRect = new Rect();        mPaint.getTextBounds(mTextString, 0, mTextString.length(), mRect);        //当前View的点击事件,显示变化的数字        this.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                mTextString = getRandomText();                //在子线程中刷新view                postInvalidate();            }        });    }    /**     * 测量自定义view,一般在view中都是这种固定的模式     *     * @param widthMeasureSpec     * @param heightMeasureSpec     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        //将测量结束的尺寸传给setMeasuredDimension方法        setMeasuredDimension(getWidthDimension(widthMeasureSpec), getHeightDimension(heightMeasureSpec));    }    /**     * 一般在自定义view中(继承View类),不需要重新布局     *     * @param changed     * @param left     * @param top     * @param right     * @param bottom     */    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);    }    /**     * 重写onDraw,重新绘制     *     * @param canvas     */    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        mPaint.setColor(Color.YELLOW);        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);        mPaint.setColor(mTextColor);        canvas.drawText(mTextString, getWidth() / 2 - mRect.width() / 2, getHeight() / 2 + mRect.height() / 2, mPaint);    }    /**     * 获取宽的测量尺寸     *     * @param _widthMeasureSpec     * @return     */    public int getWidthDimension(int _widthMeasureSpec) {        int _resultWidthDimension = 200;        int _widthMode = MeasureSpec.getMode(_widthMeasureSpec);        int _widthSize = MeasureSpec.getSize(_widthMeasureSpec);        if (MeasureSpec.EXACTLY == _widthMode) {            _resultWidthDimension = _widthSize;        } else {            _resultWidthDimension = Math.min(_widthSize, _resultWidthDimension);        }        return _resultWidthDimension;    }    /**     * 获取高的测量尺寸     *     * @param _heightMeasureSpec     * @return     */    public int getHeightDimension(int _heightMeasureSpec) {        int _resultHeightDimension = 200;        int _heightMode = MeasureSpec.getMode(_heightMeasureSpec);        int _heightSize = MeasureSpec.getSize(_heightMeasureSpec);        if (MeasureSpec.EXACTLY == _heightMode) {            _resultHeightDimension = _heightSize;        } else {            _resultHeightDimension = Math.min(_heightSize, _resultHeightDimension);        }        return _resultHeightDimension;    }    /**     * 获取一个变化的四位数     *     * @return     */    public String getRandomText() {        StringBuilder _stringBuilder = new StringBuilder();        Random _random = new Random();        Set<Integer> _set = new HashSet<>();        while (_set.size() < 4) {            int _randomInt = _random.nextInt(10);            _set.add(_randomInt);        }        for (Integer j : _set) {            _stringBuilder.append(j);        }        return _stringBuilder.toString();    }}

3、在布局中使用
重要:xmlns:mycustomview=”http://schemas.android.com/apk/res-auto”使用自定义命名空间

<com.millet.millet.CustomView.MyCustomView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        mycustomview:text_color="@color/colorPrimary"        mycustomview:text_size="20dp"        mycustomview:text_text="你好" />

4、效果
这里写图片描述

三、自定义View组合控件

(标题栏的组合)
参照Android群英传一书
1、在attrs.xml中声明属性和样式

<resources>    //自定义组合控件    <declare-styleable name="custom_view_mix">        <attr name="left_text" format="string" />        <attr name="left_text_size" format="dimension" />        <attr name="middle_text" format="string" />        <attr name="middle_text_size" format="dimension" />        <attr name="right_text" format="string" />        <attr name="right_text_size" format="dimension" />        <attr name="bg" format="color" />    </declare-styleable></resources>

2、继承ViewGroup,在构造方法中获取属性

public class MyCustomViewMix extends LinearLayout {    private String _leftString, _middleString, _rightString;    private float _leftSize, _middleSize, _rightSize;    private int _colorBg;    private TextView _leftText, _middleText, _rightText;    private LinearLayout _linear;    public MyCustomViewMix(Context context) {        this(context, null);    }    public MyCustomViewMix(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MyCustomViewMix(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //和XML中的属性建立连接        TypedArray _typeArray = context.obtainStyledAttributes(attrs, R.styleable.custom_view_mix, defStyleAttr, 0);        _leftString = _typeArray.getString(R.styleable.custom_view_mix_left_text);        _middleString = _typeArray.getString(R.styleable.custom_view_mix_middle_text);        _rightString = _typeArray.getString(R.styleable.custom_view_mix_right_text);        _leftSize = _typeArray.getDimension(R.styleable.custom_view_mix_left_text_size, (float) 15);        _middleSize = _typeArray.getDimension(R.styleable.custom_view_mix_middle_text_size, (float) 15);        _rightSize = _typeArray.getDimension(R.styleable.custom_view_mix_right_text_size, (float) 15);        _colorBg = _typeArray.getColor(R.styleable.custom_view_mix_bg, getResources().getColor(R.color.colorPrimaryDark));        //使用recycle()方法,使得可以实时获取属性值        _typeArray.recycle();        initView(context);    }    public void initView(Context _context) {        LayoutInflater.from(_context).inflate(R.layout.my_custom_view_mix, this, true);        _leftText = (TextView) findViewById(R.id.my_custom_view_mix_left);        _middleText = (TextView) findViewById(R.id.my_custom_view_mix_middle);        _rightText = (TextView) findViewById(R.id.my_custom_view_mix_right);        _linear = (LinearLayout) findViewById(R.id.my_custom_view_mix_bg);        _linear.setBackgroundColor(_colorBg);        _leftText.setText(_leftString);        _middleText.setText(_middleString);        _rightText.setText(_rightString);        _leftText.setTextSize(_leftSize);        _middleText.setTextSize(_middleSize);        _rightText.setTextSize(_rightSize);    }

3、在布局中使用
重要:xmlns:apps=”http://schemas.android.com/apk/res-auto”使用自定义命名空间

<com.millet.millet.CustomView.MyCustomViewMix        android:layout_width="match_parent"        android:layout_height="wrap_content"        apps:bg="@android:color/holo_green_dark"        apps:left_text="left"        apps:left_text_size="8dp"        apps:middle_text="middle"        apps:middle_text_size="8dp"        apps:right_text="right"        apps:right_text_size="8dp" />

4、图片效果
这里写图片描述

四、自定义View继承控件

(ListView的滑动删除)
博客:http://blog.csdn.net/guolin_blog/article/details/17357967
1、先准备一个删除的布局样式delete_button.xml

<?xml version="1.0" encoding="utf-8"?><Button xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/delete_button"    android:layout_width="match_parent"    android:layout_height="60dp"    android:background="@color/colorPrimaryDark"    android:text="删除" />

2、继承ListView类,进行添加滑动删除的功能

public class MyCustomViewExtends extends ListView implements GestureDetector.OnGestureListener, View.OnTouchListener {    //手势    private GestureDetector mGestureDetector;    private onDeleteListener mOnDeleteListener;    //当前选择的第几个    private int mSelectedItem;    //是否显示了删除按钮    private boolean mIsDeleteShown;    //ListView的Item    private ViewGroup mItemLayout;    //删除布局    private View mDeleteButton;    public MyCustomViewExtends(Context context) {        this(context, null);    }    public MyCustomViewExtends(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MyCustomViewExtends(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //初始化手势以及注册手势事件        mGestureDetector = new GestureDetector(context, this);        //注册touch事件        setOnTouchListener(this);    }    //对外留一个注册删除回调接口    public void setOndeleteListener(onDeleteListener _l) {        mOnDeleteListener = _l;    }    /*以下属于Touch事件的回调方法*/    @Override    public boolean onTouch(View v, MotionEvent event) {        //判断删除按钮是否可见,如果可见,则从ListView的Item中移除删除按钮        if (mIsDeleteShown) {            mItemLayout.removeView(mDeleteButton);            mDeleteButton = null;            mIsDeleteShown = false;            return false;        } else {            //调用手势的点击事件            return mGestureDetector.onTouchEvent(event);        }    }    /*以下属于手势的回调方法*/    @Override    public boolean onDown(MotionEvent e) {        //假如没有显示删除的布局,我们根据点击事件来计算当前点击的布局Item        if (!mIsDeleteShown) {            mSelectedItem = pointToPosition((int) e.getX(), (int) e.getY());        }        return false;    }    @Override    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {        //根据是否显示和在横向滑动的情况下处理        if (!mIsDeleteShown && Math.abs(velocityX) > Math.abs(velocityY)) {            //初始化删除按钮布局            mDeleteButton = LayoutInflater.from(getContext()).inflate(R.layout.delete_button, null);            //初始化ListView的Item            mItemLayout = (ViewGroup) getChildAt(mSelectedItem - getFirstVisiblePosition());            //在ListView的Item中放置删除按钮            RelativeLayout.LayoutParams _param = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);            _param.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);            _param.addRule(RelativeLayout.CENTER_VERTICAL);            mItemLayout.addView(mDeleteButton, _param);            //设置删除按钮为可见状态            mIsDeleteShown = true;            //点击删除按钮事件            mDeleteButton.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View v) {                    //点击删除按钮,在ListView中移除删除按钮                    mItemLayout.removeView(mDeleteButton);                    mDeleteButton = null;                    //设置删除按钮为不可见                    mIsDeleteShown = false;                    //使用回调对外传出对第几个Item进行了删除                    mOnDeleteListener.onDelete(mSelectedItem);                }            });        }        return false;    }    @Override    public void onShowPress(MotionEvent e) {    }    @Override    public boolean onSingleTapUp(MotionEvent e) {        return false;    }    @Override    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {        return false;    }    @Override    public void onLongPress(MotionEvent e) {    }    //删除监听接口    public interface onDeleteListener {        void onDelete(int _index);    }}

3、在布局中使用

<com.millet.millet.CustomView.MyCustomViewExtends        android:id="@+id/activity_my_custom_list_view"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:dividerHeight="2dp" />

4、在Activity中使用

public class MyCustomListView extends BaseActivity {    private MyCustomViewExtends mMyCustomViewExtends;    private MyCustomListViewAdapter mMyCustomListViewAdapter;    private List<String> mList = new ArrayList<>();    @Override    public void initData(Bundle savedInstanceState) {        for (int i = 0; i < 20; i++) {            mList.add("Millet" + i);        }    }    @Override    public void initView(Bundle savedInstanceState) {        setContentView(R.layout.activity_my_custom_list_view);        mMyCustomViewExtends = (MyCustomViewExtends) findViewById(R.id.activity_my_custom_list_view);        mMyCustomListViewAdapter = new MyCustomListViewAdapter(this, 0, mList);        mMyCustomViewExtends.setAdapter(mMyCustomListViewAdapter);        mMyCustomViewExtends.setOndeleteListener(new MyCustomViewExtends.onDeleteListener() {            @Override            public void onDelete(int _index) {                mList.remove(_index);                mMyCustomListViewAdapter.notifyDataSetChanged();            }        });    }    @Override    public void loadData(Bundle savedInstanceState) {    }    public class MyCustomListViewAdapter extends ArrayAdapter {        public MyCustomListViewAdapter(Context context, int resource, List<String> objects) {            super(context, resource, objects);        }        @NonNull        @Override        public View getView(int position, View convertView, ViewGroup parent) {            View _view;            if (null == convertView) {                _view = getLayoutInflater().inflate(R.layout.my_list_view_item, null);            } else {                _view = convertView;            }            TextView _textView = (TextView) _view.findViewById(R.id.my_list_view_item_text);            _textView.setText((String) getItem(position));            return _view;        }    }}

5、图片效果
这里写图片描述

0 0