多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > Android 從0開始自定義控件之 自定義 View 基礎(chǔ)實(shí)例(十)

Android 從0開始自定義控件之 自定義 View 基礎(chǔ)實(shí)例(十)

來源:程序員人生   發(fā)布時(shí)間:2017-02-11 13:26:29 閱讀次數(shù):2800次

轉(zhuǎn)載請(qǐng)標(biāo)明出處: http://blog.csdn.net/airsaid/article/details/54294144
本文出自:周游的博客

  • 前言
  • 自定義 View 分類
    • 繼承 View
    • 繼承 ViewGroup
    • 繼承已有 View
    • 繼承已有布局
  • 自定義 View 實(shí)例
    • 繼承 View 的實(shí)例
    • 繼承 ViewGroup 實(shí)例
    • 繼承已有 View 實(shí)例
    • 繼承已有 ViewGroup 實(shí)例
  • 源碼下載

前言

在前面的博客當(dāng)中,我們學(xué)習(xí)了 View 的1些工作原理知識(shí)等,現(xiàn)在是時(shí)候來寫1波實(shí)例了,畢竟實(shí)踐出真知嘛~ 在開始寫實(shí)例之前,首先來了解下自定義 View 到底有哪幾種吧,然后再根據(jù)每種分別寫1個(gè)簡(jiǎn)單的小栗子。

自定義 View 分類

在我們準(zhǔn)備編寫1個(gè)自定義 View 的時(shí)候,我們需要根據(jù)我們的需求來編寫不同的自定義 View。比如說,如果只是想對(duì) TextView 進(jìn)行擴(kuò)大,那末可以繼承自 TextView 來編寫1個(gè)新的 View,如果想自己定義1個(gè)不同的布局,那末可以繼承 ViewGroup 來實(shí)現(xiàn)。那末到底有多少類的自定義 View 呢?在網(wǎng)上搜了下,發(fā)現(xiàn)大都是說3種、或4種,感覺自定義 View 的分類標(biāo)準(zhǔn)其實(shí)不1,在這里的話還是以主席的為準(zhǔn)分為4類吧,感覺更細(xì)分1些,這4類分別是:

繼承 View

當(dāng)我們需要實(shí)現(xiàn)的效果是1個(gè)不規(guī)則效果的時(shí)候,那末這時(shí)候就需要繼承 View 來實(shí)現(xiàn)了,我們需要重寫 onDraw 方法,在該方法里實(shí)現(xiàn)各種不規(guī)則的圖形和效果。當(dāng)我們使用這類方式的時(shí)候,需要自己去處理 warp_content 和 padding。

繼承 ViewGroup

當(dāng)系統(tǒng)所提供的 LinearLayout、FrameLayout 等布局控件沒法滿足我們的需求時(shí),這時(shí)候我們就需要使用這類方式來實(shí)現(xiàn)自己想要的布局效果了。當(dāng)我們使用這類方式的時(shí)候,需要重寫 onLayout 方法來對(duì)子 View 進(jìn)行布局,和丈量本身和子 View 寬高,還需要處理本身的 padding 和子 View 的 margin。

繼承已有 View

當(dāng)我們需要基于已有的 View 進(jìn)行擴(kuò)大或修改的時(shí)候,那末就能夠使用這類方式。比如說,我們需要1個(gè)圓角的 ImageView,那末這時(shí)候就能夠繼承 ImageView 進(jìn)行修改了。當(dāng)我們使用這類方式的時(shí)候,1般不需要自己去處理 wrap_content 和 padding 等,由于系統(tǒng)控件已幫我們做好了。

繼承已有布局

這類方式也叫做:自定義組合 View。該方式比較簡(jiǎn)單,當(dāng)我們需要將1組 View 組合在1起,方便后期復(fù)用的時(shí)候,就能夠使用該方法。當(dāng)我們使用這類方式的時(shí)候,不需要去處理 ViewGroup 的丈量和布局流程,由于系統(tǒng)控件已幫我們做好了。

自定義 View 實(shí)例

上面我們了解了自定義 View 的4種分類,下面我們分別寫4個(gè)與分類對(duì)應(yīng)的小栗子來了解下其各自的寫法,和1些需要注意的問題。

繼承 View 的實(shí)例

當(dāng)我們自定義 View 繼承子 View 時(shí),我們需要注意的細(xì)節(jié)有:

  • View 是 wrap_contetn 時(shí)需要手動(dòng)丈量 View 寬高。
  • View 有 padding 值時(shí)需要處理。

在這個(gè)實(shí)例當(dāng)中,我們只需簡(jiǎn)單的畫1個(gè)圓便可。重點(diǎn)是細(xì)節(jié)上的處理,寫出1個(gè)規(guī)范的自定義 View。

實(shí)例代碼以下:

public class CircleView extends View {

    private Paint mPaint;

    /** 圓半徑 */
    private float mRadius = 50;

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

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

    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // 初始化畫筆
        mPaint = new Paint();
        mPaint.setColor(Color.BLUE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int width = getWidth();
        int height = getHeight();
        canvas.drawCircle(width / 2, height / 2,  mRadius, mPaint);
    }
}

上面的自定義 View 實(shí)例很簡(jiǎn)單,就是繪制了1個(gè)圓形。放在布局中,運(yùn)行看下效果:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.airsaid.customviewdemo.widget.CircleView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#999999"/>

</RelativeLayout

運(yùn)行結(jié)果:
這里寫圖片描述
雖然我們已實(shí)現(xiàn)了1個(gè)簡(jiǎn)單的繼承 View 的自定義 View,但該自定義 View 還不是1個(gè)規(guī)范的自定義 View,比如此時(shí)我們把布局改動(dòng)1下,將 View 的寬高改成 wrap_content 和增加 padding 和 margin 屬性:

<com.airsaid.customviewdemo.widget.CircleView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="15dp"
    android:background="#999999"
    android:padding="15dp"/>

重新運(yùn)行結(jié)果:
這里寫圖片描述

可以看到,雖然我們重新修改了寬高 為 wrap_content,和增加了 padding 和 margin ,但是終究生效的只有 margin。其他的1概沒有生效,而 wrap_content 居然和 match_parent 1樣。這是怎樣1回事呢?

這是由于,margin 是由父控件來控制的,所以我們不需要進(jìn)行處理,但是我們需要對(duì) View 的 padding 和 LayoutParams 是 wrap_content 的情況進(jìn)行處理,否則 padding 將會(huì)沒法生效、wrap_content 的效果會(huì)和 match_parent 1樣,具體產(chǎn)生這樣的緣由可以看深入理解 MeasureSpec這篇文章。

下面我們重寫修改下,在 onDraw 繪制時(shí),加上 padding 值,代碼以下:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    int paddingLeft = getPaddingLeft();
    int paddingTop = getPaddingTop();
    int paddingRight = getPaddingRight();
    int paddingBottom = getPaddingBottom();

    int width = getWidth() - paddingLeft - paddingRight;
    int height = getHeight() - paddingTop - paddingBottom;
    canvas.drawCircle(width / 2 + paddingLeft, height / 2 + paddingTop,  mRadius, mPaint);
}

重寫 onMeasure 方法,判斷當(dāng)是 wrap_content 的情況時(shí),自己丈量 View 的寬或高:

@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);

    if(widthMode == MeasureSpec.AT_MOST){
        widthSize = (int) (mRadius * 2 + getPaddingLeft() + getPaddingRight());
    }

    if(heightMode == MeasureSpec.AT_MOST){
        heightSize = (int) (mRadius * 2 + getPaddingTop() + getPaddingBottom());
    }

    setMeasuredDimension(widthSize, heightSize);
}

重新運(yùn)行:
這里寫圖片描述

可以看到,padding 和 wrap_content 都已生效了,這時(shí)候候才是1個(gè)規(guī)范的自定義 View,但是此時(shí)這個(gè)自定義 View 其實(shí)不完善,下篇在自定義屬性文章中將會(huì)完善它,給它加入自定義屬性。

繼承 ViewGroup 實(shí)例

當(dāng)我們自定義 View 繼承自 ViewGroup 時(shí),就需要去實(shí)現(xiàn) onLayout 方法來指定子 View 的擺放位置,并且需要重寫 onMeasure 方法來丈量大小。在這個(gè)實(shí)例當(dāng)中,我們簡(jiǎn)單模仿下 LinearLayout ,只不過只實(shí)現(xiàn)其 Vertical 模式,在這個(gè)實(shí)例當(dāng)中,我們需要注意的細(xì)節(jié)有:

  • ViewGroup 是 wrap_conent 時(shí)需要手動(dòng)丈量。
  • 當(dāng) ViewGroup 本身有 padding 值時(shí)需要處理。
  • 當(dāng)子 View 有 margin 值時(shí)需要處理。

作為1個(gè)規(guī)范的自定義 ViewGroup ,這幾個(gè)細(xì)節(jié)我們都需要去處理,下面直接上代碼:


/**
 * 作者: 周游
 * 時(shí)間: 2017/1/8
 * 博客: http://blog.csdn.net/airsaid
 * 描寫: 1個(gè)繼承 ViewGroup 的自定義 View 入門實(shí)例,該 ViewGroup 垂直擺放子 View。
 */
public class SimpleVerticalLayout extends ViewGroup {

    private final Context mContext;

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

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

    public SimpleVerticalLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 獲得 ViewGroup 的丈量模式、大小。
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        // 獲得 ViewGroup 的 padding 值
        int pl = getPaddingLeft();
        int pt = getPaddingTop();
        int pr = getPaddingRight();
        int pb = getPaddingBottom();

        // 丈量所有子 View,當(dāng)丈量后才能獲得到子 View 的丈量寬高
        measureChildren(widthMeasureSpec, heightMeasureSpec);

        // 自己計(jì)算的 ViewGroup 的寬高
        int width = 0;
        int height = 0;

        // 判斷如果 ViewGroup 的寬度是 wrap_content
        if(widthMode == MeasureSpec.AT_MOST){
            // 計(jì)算 ViewGroup 的寬度,遍歷所有子 View,最寬的那個(gè) View 的寬度就是 ViewGroup 的寬度
            int maxWidth = 0;
            for (int i = 0; i < getChildCount(); i++) {
                View childAt = getChildAt(i);
                if(childAt.getVisibility() == View.GONE){
                    continue;
                }

                MarginLayoutParams lp = (MarginLayoutParams) childAt.getLayoutParams();
                int childWidth = childAt.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
                maxWidth = childWidth > maxWidth ? childWidth : maxWidth;
            }
            width = maxWidth + pl + pr;
        }

        // 判斷如果 ViewGroup 的高度是 wrap_content
        if(heightMode == MeasureSpec.AT_MOST){
            // 計(jì)算 ViewGroup 的高度,由因而垂直擺放,所以高度為每一個(gè)子 View 的高度和
            for (int i = 0; i < getChildCount(); i++) {
                View childAt = getChildAt(i);
                if(childAt.getVisibility() == View.GONE){
                    continue;
                }

                MarginLayoutParams lp = (MarginLayoutParams) childAt.getLayoutParams();
                height += childAt.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            }
            height = height + pt + pb;
        }

        setMeasuredDimension(widthMode == MeasureSpec.AT_MOST ? width : widthSize
                , heightMode == MeasureSpec.AT_MOST ? height : heightSize);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int pl = getPaddingLeft();
        int pt = getPaddingTop();
        int pr = getPaddingRight();
        int pb = getPaddingBottom();


        int cl = 0;
        int ct = 0;
        int cr = 0;
        int cb = 0;
        int bm = 0;

        // 遍歷所有子 View
        int childCount = getChildCount();

        for (int i = 0; i < childCount; i++) {
            // 獲得子 View
            View childAt = getChildAt(i);
            // 判斷當(dāng)子 View 沒有 Gone 掉時(shí)
            if(childAt.getVisibility() != View.GONE){
                // 計(jì)算每一個(gè)子 View 的位置
                MarginLayoutParams lp = (MarginLayoutParams) childAt.getLayoutParams();
                cl = lp.leftMargin;
                ct += lp.topMargin;
                cr = childAt.getMeasuredWidth() + lp.leftMargin;
                cb += childAt.getMeasuredHeight() + lp.topMargin;
                // 對(duì)子 View 進(jìn)行布局
                childAt.layout(cl + pl, ct + pt + bm, cr + pr, cb + pb + bm);
                ct += childAt.getMeasuredHeight();
                bm += lp.bottomMargin;
            }
        }
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(mContext, attrs);
    }
}

上面的代碼實(shí)現(xiàn)的很簡(jiǎn)單,并且注釋也很詳細(xì)。我們直接放到布局中看看效果:

<com.airsaid.customviewdemo.widget.SimpleVerticalLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#999999"
    android:padding="10dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:background="#ff0000"
        android:text="我是第1個(gè)子 View"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ffff00"
        android:text="我是第2個(gè)子 View"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:text="我是第3個(gè)子 View"/>
</com.airsaid.customviewdemo.widget.SimpleVerticalLayout>

運(yùn)行結(jié)果:
這里寫圖片描述
可以看到,SimpleVerticalLayout 的 padding,和子 View 的 margin 都是生效的。

繼承已有 View 實(shí)例

當(dāng)我們自定義 View 繼承自系統(tǒng)已有 View 時(shí),1般是基于其原有功能進(jìn)行擴(kuò)大或修改。比如這個(gè)實(shí)例當(dāng)中,我們對(duì)原本的 EditText 進(jìn)行擴(kuò)大,增加1個(gè)有內(nèi)容時(shí)顯示刪除按鈕,點(diǎn)擊按鈕清空文本的 EditText,實(shí)例很簡(jiǎn)單,仍然直接貼代碼了:


/**
 * 作者: 周游
 * 時(shí)間: 2017/1/9
 * 博客: http://blog.csdn.net/airsaid
 * 描寫: 1個(gè)繼承已有 View 的自定義 View 實(shí)例,帶清除按鈕的 EditText。
 */
public class CleanEditText extends EditText{

    private final Context mContext;
    private Drawable mDeleteDrawable;

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

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

    public CleanEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;

        // 設(shè)置右邊刪除圖標(biāo)
        mDeleteDrawable = getResources().getDrawable(R.mipmap.ic_delete);
        // 添加監(jiān)聽
        addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {}

            @Override
            public void afterTextChanged(Editable s) {
                setDeleteDrawable();
            }
        });
        setDeleteDrawable();
    }

    private void setDeleteDrawable() {
        setCompoundDrawablesWithIntrinsicBounds(null, null, length() > 0 ? mDeleteDrawable : null, null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_UP){
            if(mDeleteDrawable != null){
                int rawX = (int) event.getRawX();
                int rawY = (int) event.getRawY();
                Rect rect = new Rect();
                getGlobalVisibleRect(rect);
                rect.left = rect.right - 50;
                if(rect.contains(rawX, rawY))
                    setText("");
            }
        }
        return super.onTouchEvent(event);
    }
}

運(yùn)行結(jié)果:
這里寫圖片描述

繼承已有 ViewGroup 實(shí)例

這類自定義 View 的實(shí)現(xiàn)方式也叫做:“自定義組合控件”,是1種比較簡(jiǎn)單的自定義 View 方式。使用這類方式時(shí),由因而繼承已有的系統(tǒng)控件,所以我們不需去丈量、布局、處理 margin、padding等,由于系統(tǒng)控件本身已處理好了。

當(dāng)我們的項(xiàng)目中有1些布局在很多地方都要用到的話,那末第1時(shí)間肯定就要想到復(fù)用了。復(fù)用的話,有人可能會(huì)想到使用 include 復(fù)用布局,但是如果這樣的話,當(dāng)布局改動(dòng)性很大時(shí),使用 include 其實(shí)不是很靈活。這時(shí)候候,就能夠使用 ”繼承已有 ViewGroup“ 這類方式了。

下面1個(gè)實(shí)例,就拿我們平時(shí)可能常常要寫的 Item 為例吧:


/**
 * 作者: 周游
 * 時(shí)間: 2017/1/9
 * 博客: http://blog.csdn.net/airsaid
 * 描寫: 1個(gè)繼承已有 ViewGroup 的自定義 View 實(shí)例,經(jīng)常使用 item 布局。
 */
public class CustomItemLayout extends FrameLayout {

    private TextView mTxtLeft;
    private TextView mTxtRight;
    private ImageView mImgRight;

    private Context mContext;
    // 左邊文字
    private String mLeftText;
    // 右邊文字
    private String mRightText;
    // 右邊文字色彩
    private int mRightTextColor = Color.parseColor("#666666");
    // 右邊圖片
    private int mRightImageId = R.mipmap.ic_arrow_right;
    // 左邊圖片
    private Drawable mLeftImage = null;

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

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

    public CustomItemLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        initAttrs(attrs);
        initView();
        setData();
    }

    private void initAttrs(AttributeSet attrs) {
        // 獲得自定義屬性
        TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.CustomItemLayout);
        mLeftText = a.getString(R.styleable.CustomItemLayout_item_leftText);
        mRightText = a.getString(R.styleable.CustomItemLayout_item_rightText);
        mRightTextColor = a.getColor(R.styleable.CustomItemLayout_item_rightTextColor, mRightTextColor);
        mRightImageId = a.getResourceId(R.styleable.CustomItemLayout_item_rightImage, mRightImageId);
        mLeftImage = a.getDrawable(R.styleable.CustomItemLayout_item_leftImage);
        a.recycle();
    }

    private void initView() {
        // 加載自定義布局到當(dāng)前 ViewGroup
        LayoutInflater.from(mContext).inflate(R.layout.view_custom_item_layout, this);
        mTxtLeft = (TextView) findViewById(R.id.txt_left);
        mTxtRight = (TextView) findViewById(R.id.txt_right);
        mImgRight = (ImageView) findViewById(R.id.img_right);
    }

    private void setData() {
        if(mLeftText != null)   mTxtLeft.setText(mLeftText);
        if(mRightText != null)  mTxtRight.setText(mRightText);
        setRightImage(mRightImageId);
        if(mLeftImage != null)
            mLeftImage.setBounds(0, 0, dp2px(22), dp2px(12));
        mTxtLeft.setCompoundDrawables(null, null, mLeftImage, null);
    }

    public void setRightTextColor(int resId){
        mTxtRight.setTextColor(resId);
    }

    public void setRightText(String text){
        mTxtRight.setText(text);
    }

    public void setRightText(int resId){
        mTxtRight.setText(resId);
    }

    public String getRightText(){
        return mTxtRight.getText().toString();
    }

    public void setLeftImage(int leftImageId){
        mLeftImage = getResources().getDrawable(leftImageId);
        setData();
    }

    public void setRightImage(int rightImageId){
        if(rightImageId != -1){
            mImgRight.setVisibility(View.VISIBLE);
            mImgRight.setImageResource(rightImageId);
        }else{
            mImgRight.setVisibility(View.GONE);
        }
    }

    private int dp2px(float dpValue){
        return (int)(dpValue * (getResources().getDisplayMetrics().density) + 0.5f);
    }
}

首先自定義1個(gè)類,繼承自 FrameLayout,固然,這里你也能夠選擇繼承 LinearLayout 或其他,根據(jù)具體需求來。其中在構(gòu)造中獲得了自定義屬性,和填充了布局。自定義屬性有不懂的同學(xué)可以先疏忽,下篇會(huì)單獨(dú)拿出來寫1篇。

最主要的地方就是填充布局那里,將布局填充到了當(dāng)前控件也就是自定義的 ViewGroup 上。填充的布局以下:

<?xml version="1.0" encoding="utf⑻"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:background="?android:selectableItemBackground"
              android:gravity="center_vertical"
              android:padding="15dp">

    <TextView
        android:id="@+id/txt_left"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawablePadding="5dp"
        android:ellipsize="end"
        android:maxLines="1"
        android:textColor="@color/text_black"
        android:textSize="@dimen/txt14"/>

    <TextView
        android:id="@+id/txt_right"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_weight="1"
        android:ellipsize="end"
        android:gravity="right"
        android:maxLines="1"
        android:textSize="@dimen/txt14"/>

    <ImageView
        android:id="@+id/img_right"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:src="@mipmap/ic_arrow_right"/>
</LinearLayout>

使用時(shí),可以直接在布局中通過自定義屬性設(shè)置數(shù)據(jù):

<com.airsaid.customviewdemo.widget.CustomItemLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:item_leftText="版本更新"
    app:item_rightImage="@mipmap/ic_arrow_right"
    app:item_rightText="V1.1"/>

也能夠通過暴露的方法設(shè)置數(shù)據(jù),怎樣方便怎樣來。

運(yùn)行結(jié)果:
這里寫圖片描述

源碼下載

CSDN:http://download.csdn.net/detail/airsaid/9733175

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 亚洲国产精品综合久久一线 | 国产视频一区二区在线观看 | 日本中文字幕视频 | 综合激情区视频一区视频二区 | 性欧美xxxx视频 | 国产中文字幕第一页 | 久久久久国产一级毛片高清版 | jizz中国18| 国产福利一区二区三区在线视频 | 性色免费视频 | 免费一区二区三区四区五区 | 午夜在线a亚洲v天堂网2019 | 九九精品免视频国产成人 | 最新中文字幕一区二区乱码 | 亚洲性网 | 国产亚洲欧美在线 | 亚洲图片偷拍区 | 亚洲最新永久在线观看 | 日韩 欧美 亚洲国产 | 国产亚洲精品片a77777 | 中文字幕亚洲综合久久2 | 午夜dj在线观看免费高清在线 | 精品一区二区三区无卡乱码 | 在线免费观看福利 | 国产一级淫片a | 福利视频一二区 | 国产精品久久久久国产精品 | 精品高清国产a毛片 | 福利视频一区二区三区 | 国产午夜亚洲精品一级在线 | 亚洲综合在线播放 | 欧美一区二区精品系列在线观看 | 男人天堂亚洲色图 | 羞羞动漫在线免费观看 | 国产欧美日韩另类va在线 | 成人资源在线观看 | 亚州都市春色校园小说另类 | 天堂亚洲欧美日韩一区二区 | 国产精品久久成人影院 | 网站在线观看免费视频 | 欧美羞羞视频 |