自定義View,繪制

1.使用繪制方法,畫(huà)出一個(gè)view,然后在xml文件中使用即可

1.創(chuàng)建自定義的view
這里我只畫(huà)了一個(gè)空心圓,canvas是畫(huà)布,paint是畫(huà)筆,用畫(huà)筆可以畫(huà)出任何圖形設(shè)置顏色、空心實(shí)心、線(xiàn)條寬度,通過(guò)RectF設(shè)置圓的位置和大小

public class PaintView extends View {

    public PaintView(Context context) {
        super(context);
    }

    public PaintView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

        RectF rectF = new RectF(10, 10, 100, 100);
        Paint paint = new Paint();

        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(10);

        canvas.drawOval(rectF, paint);
    }
}

2.將畫(huà)好的view引用到xml中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.mazhan.view.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.mazhan.view.PaintView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

這樣我們繪制的view就可以被加載出來(lái)了


Snip20201022_18.png

2.繪制線(xiàn)條時(shí)的注意點(diǎn)
1.需要設(shè)置stroke
2.二階的貝塞爾曲線(xiàn)可以設(shè)置跟隨手勢(shì)畫(huà)出任意的圖形,這個(gè)在線(xiàn)教育中使用的畫(huà)板就是使用的二階貝塞爾曲線(xiàn)

public class CanvasPathView extends View {
    public CanvasPathView(Context context) {
        super(context);
    }

    public CanvasPathView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(10);
        // 如果需要繪制path的話(huà),需要設(shè)置paint的style為stroke
        paint.setStyle(Paint.Style.STROKE);

        // 線(xiàn)條需要通過(guò)path來(lái)繪制
        Path path = new Path();
        // 設(shè)置起點(diǎn)
        path.moveTo(50,50);
        // 設(shè)置連接點(diǎn)
        path.lineTo(100,100);

        //二階貝塞爾曲線(xiàn)
        path.quadTo(200,200,300,100);

        canvas.drawPath(path, paint);
    }
}
Snip20201022_20.png

3.移動(dòng)坐標(biāo)系

默認(rèn)的坐標(biāo)系是(0,0),可以通過(guò)設(shè)置canvas的屬性來(lái)平移或者是旋轉(zhuǎn)坐標(biāo)系,然后將坐標(biāo)系的模式保存下來(lái),這樣可以便利的設(shè)置一些特殊的坐標(biāo)系

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

        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.RED);
        paint.setStrokeWidth(10);

        // 設(shè)置坐標(biāo)系起始點(diǎn)為100,100
        canvas.translate(100,100);

        // 保存設(shè)置好的坐標(biāo)系
        canvas.save();

        // 設(shè)置坐標(biāo)系旋轉(zhuǎn)
        canvas.rotate(90);

        // 銷(xiāo)毀坐標(biāo)系,還原上一次保存的坐標(biāo)系
        canvas.restore();

        canvas.drawLine(0,0,100,0,paint);
    }

4.自定義控件的三大方法執(zhí)行順序

public class MyFrameLayout extends FrameLayout {

    public MyFrameLayout(@NonNull Context context) {
        super(context);
    }

    public MyFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

        Log.d(getClass().getSimpleName(), "onDraw: " + "MyFrameLayout父控件");
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        Log.d(getClass().getSimpleName(), "onMeasure: " +  "MyFrameLayout父控件");
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        Log.d(getClass().getSimpleName(), "onLayout: " +  "MyFrameLayout父控件");
    }
}


public class MyView extends View {

    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

        Paint paint = new Paint();
        paint.setTextSize(20);
        canvas.drawText("這是一個(gè)view", 10, 10, paint);

        Log.d(getClass().getSimpleName(), "onDraw: " + "MyView子控件");

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        Log.d(getClass().getSimpleName(), "onMeasure: " + "MyView子控件");

    }


    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        Log.d(getClass().getSimpleName(), "onLayout: " + "MyView子控件");

    }
}

在xml中使用MyFrameLayout和MyView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.mazhan.customviewmethodorder.MainActivity">

    <com.mazhan.customviewmethodorder.MyFrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <com.mazhan.customviewmethodorder.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    </com.mazhan.customviewmethodorder.MyFrameLayout>

</LinearLayout>
10-22 07:20:51.088 6735-6735/com.mazhan.customviewmethodorder D/MyFrameLayout: onMeasure: MyFrameLayout父控件
10-22 07:20:51.150 6735-6735/com.mazhan.customviewmethodorder D/MyFrameLayout: onMeasure: MyFrameLayout父控件
10-22 07:20:51.153 6735-6735/com.mazhan.customviewmethodorder D/MyFrameLayout: onLayout: MyFrameLayout父控件
10-22 07:28:38.713 6928-6928/com.mazhan.customviewmethodorder D/MyFrameLayout: onMeasure: MyFrameLayout父控件
                                                                              
10-22 07:28:38.753 6928-6928/com.mazhan.customviewmethodorder D/MyFrameLayout: onMeasure: MyFrameLayout父控件
10-22 07:28:38.760 6928-6928/com.mazhan.customviewmethodorder D/MyFrameLayout: onLayout: MyFrameLayout父控件
10-22 07:30:32.941 7079-7079/com.mazhan.customviewmethodorder D/MyView: onMeasure: MyView子控件
10-22 07:30:32.943 7079-7079/com.mazhan.customviewmethodorder D/MyFrameLayout: onMeasure: MyFrameLayout父控件
                                                                               
10-22 07:30:32.995 7079-7079/com.mazhan.customviewmethodorder D/MyView: onMeasure: MyView子控件
10-22 07:30:32.995 7079-7079/com.mazhan.customviewmethodorder D/MyFrameLayout: onMeasure: MyFrameLayout父控件
10-22 07:30:32.996 7079-7079/com.mazhan.customviewmethodorder D/MyView: onLayout: MyView子控件
10-22 07:30:32.996 7079-7079/com.mazhan.customviewmethodorder D/MyFrameLayout: onLayout: MyFrameLayout父控件
10-22 07:30:33.188 7079-7079/com.mazhan.customviewmethodorder D/MyView: onDraw: MyView子控件

5.VierPager的使用

1.在MainActivity的xml中添加ViewPager

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" tools:context="com.mazhan.viewpagerdemo.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPagerId"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_purple">


    </android.support.v4.view.ViewPager>


</LinearLayout>

2.給ViewPager設(shè)置PagerAdapter

public class MainActivity extends AppCompatActivity {

    private ArrayList<TextView> mDatas;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initData();
        initViews();
    }

    private void initViews() {
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewPagerId);

        viewPager.setAdapter(new PagerAdapter() {
            @Override
            public int getCount() {
                return mDatas.size();
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {

                TextView textView =  mDatas.get(position);
                container.addView(textView);
                return textView;
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {

                container.removeView((View) object);
            }
        });
    }

    private void initData() {
        mDatas = new ArrayList<>();
        for (int i = 0; i < 10; i++) {

            TextView textView = new TextView(getApplicationContext());
            textView.setTextSize(20);
            textView.setText("這是第" + i + "個(gè)頁(yè)面");
            mDatas.add(textView);
        }
    }
}

6.ViewFliper的使用
使用viewFlipper完成文字向上滾動(dòng)的效果(只要設(shè)置滾動(dòng)的動(dòng)畫(huà)即可)

在xml中直接使用系統(tǒng)的ViewFlipper即可

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" tools:context="com.mazhan.viewfliperdemo.MainActivity">

    <ViewFlipper
        android:id="@+id/ViewFlipperId"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/myColorRed">
    </ViewFlipper>

</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

    }

    private void initView() {
        ViewFlipper viewFlipper = (ViewFlipper) findViewById(R.id.ViewFlipperId);
        viewFlipper.startFlipping();

        //設(shè)置viewFlipper的一些屬性
        viewFlipper.setFlipInterval(5000);

        // 設(shè)置viewFlipper的的入場(chǎng)動(dòng)畫(huà)和離場(chǎng)動(dòng)畫(huà)
        // 組合動(dòng)畫(huà)   透明度  位移
        // 離場(chǎng)動(dòng)畫(huà)
        AnimationSet inAnimationSet = new AnimationSet(false);
        AnimationSet outAnimationSet = new AnimationSet(false);

        AlphaAnimation inAlphaAnimation = new AlphaAnimation(0, 1);
        TranslateAnimation inTranslateAnimation = new TranslateAnimation(
                TranslateAnimation.RELATIVE_TO_SELF, 0,
                TranslateAnimation.RELATIVE_TO_SELF, 0,
                TranslateAnimation.RELATIVE_TO_SELF, 1,
                TranslateAnimation.RELATIVE_TO_SELF, 0);
        inAnimationSet.addAnimation(inAlphaAnimation);
        inAnimationSet.addAnimation(inTranslateAnimation);
        inAnimationSet.setDuration(3000);


        AlphaAnimation outAlphaAnimation = new AlphaAnimation(1, 0);
        TranslateAnimation outTranslateAnimation = new TranslateAnimation(
                TranslateAnimation.RELATIVE_TO_SELF, 0,
                TranslateAnimation.RELATIVE_TO_SELF, 0,
                TranslateAnimation.RELATIVE_TO_SELF, 0,
                TranslateAnimation.RELATIVE_TO_SELF, -1);
        outAnimationSet.addAnimation(outAlphaAnimation);
        outAnimationSet.addAnimation(outTranslateAnimation);
        outAnimationSet.setDuration(2000);

        viewFlipper.setInAnimation(inAnimationSet);
        viewFlipper.setOutAnimation(outAnimationSet);

        //向ViewFlipper中添加要滾動(dòng)的view
        for (int i = 0; i < 10; i++) {
            TextView textView = new TextView(getApplicationContext());
            textView.setText("這是第" + i + "個(gè)textView");
            viewFlipper.addView(textView);
        }
    }
}

7.自定義控件自定義屬性

1.比如說(shuō)自定義一個(gè)只滾動(dòng)text的ViewFlipper,叫做textViewFlipper。如果要給這個(gè)控件添加自定義屬性,那么需要新建一個(gè)文件


image.png

2.那么如何在xml中使用自定義的屬性呢


image.png

3.這樣在自定義的控件類(lèi)被加載的時(shí)候,就會(huì)調(diào)用構(gòu)造方法,那么就可以得到自定義的屬性名和屬性值


image.png

4.將自定義的屬性設(shè)置給textView
這里自定義屬性的獲取方式并不是這樣遍歷的,是直接通過(guò)字段獲取的,R.styleable,R.styleable.TextViewFlipper_fontColor,R.styleable.TextViewFlipper_fontSize,這些都是系統(tǒng)根據(jù)自定義屬性的文件生成的。

注意點(diǎn):這里獲取屬性的時(shí)機(jī)是要注意的,只能在構(gòu)造方法里進(jìn)行獲取,只有在構(gòu)造方法被調(diào)用的時(shí)候,attrs的值才是正確的,當(dāng)構(gòu)造方法執(zhí)行完成之后,attrs的值會(huì)發(fā)生變化,也就得不到自定義的屬性了。


public class TextViewFlipper extends ViewFlipper {

    private AttributeSet mAttrs;
    private Context mContext;
    private float mTextSize;
    private int mTextColor;

    public TextViewFlipper(Context context) {
        super(context);
    }

    public TextViewFlipper(Context context, AttributeSet attrs) {
        super(context, attrs);

        mContext = context;
        mAttrs = attrs;

        int attributeCount = attrs.getAttributeCount();
        for (int i = 0; i < attributeCount; i++) {
            String attributeName = attrs.getAttributeName(i);
            String attributeValue = attrs.getAttributeValue(i);

            Log.d(getClass().getSimpleName(), "TextFlipperView: attributeName: " + attributeName
                    +" attributeValue: "+attributeValue);
        }

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextViewFlipper);
        mTextColor = typedArray.getColor(R.styleable.TextViewFlipper_fontColor, Color.BLACK);
        mTextSize = typedArray.getDimension(R.styleable.TextViewFlipper_fontSize, 100);
        //銷(xiāo)毀typedArray 
        typedArray.recycle();
    }


    void setViews (ArrayList<TextView> textViews) {

        for (int i = 0; i < textViews.size(); i++) {
            TextView textView = textViews.get(i);
            textView.setTextColor(mTextColor);
            textView.setTextSize(mTextSize);
            addView(textView);
        }
    }

}

8.制作垂直滑動(dòng)的滑塊demo
自定義VerticalSlideView,里面放一個(gè)ImageView,讓imageView跟隨手指拖動(dòng)而滑動(dòng)


public class VerticalSlideView extends ViewGroup {

    private View mChildView;
    private float mStartY;
    private float mStartX;


    public VerticalSlideView(Context context) {
        super(context);
    }

    public VerticalSlideView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    // 確定控件的大小
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        mChildView = getChildAt(0);

        //1. 獲得mode和size
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int withSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        // 測(cè)量自控件的寬度
        measureChildren(widthMeasureSpec, heightMeasureSpec);

        // 2.判斷mode,根據(jù)mode來(lái)設(shè)置size
        int childWidth = mChildView.getMeasuredWidth();

        // 設(shè)置自身控件的大小
        setMeasuredDimension(childWidth, heightSize - dip2px(10));
    }


    // 對(duì)子控件進(jìn)行布局
    int mTop = 0;
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // 位置:左上右下
        mChildView.layout(0, mTop, mChildView.getMeasuredWidth(), mTop+mChildView.getMeasuredHeight());
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {

        // 這里沒(méi)有判斷action的類(lèi)型,是點(diǎn)擊還是滑動(dòng)還是抬起
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                // do sth
                break;

            case MotionEvent.ACTION_MOVE:
                // do sth
                break;
            case MotionEvent.ACTION_UP:
                // do sth
                break;
            default:
                break;
        }

        // 直接設(shè)置滑塊的y值跟隨觸摸的y值變化
        float y = event.getY();
        mTop = (int) y;
        requestLayout();

        if (y < 0) {
            mTop = 0;
        }

        if (y > getMeasuredHeight() - mChildView.getMeasuredHeight()) {
            mTop =  getMeasuredHeight() - mChildView.getMeasuredHeight();
        }

        requestLayout();
        return true;
    }



    public int px2dip(float pxValue) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    // 將do轉(zhuǎn)化為像素尺寸
    public int dip2px( float dpValue) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

在xml中使用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" tools:context="com.mazhan.verticalslideview.MainActivity">

    <com.mazhan.verticalslideview.VerticalSlideView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="20dp"
        android:background="#f00">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/tabicon"/>
    </com.mazhan.verticalslideview.VerticalSlideView>

</LinearLayout>

9.無(wú)限滾動(dòng)的背景View
通過(guò)繪制背景圖片來(lái)實(shí)現(xiàn)

1.創(chuàng)建自定義的屬性,來(lái)設(shè)置圖片滾動(dòng)的參數(shù),創(chuàng)建attrs屬性文件,設(shè)置參數(shù)

  <?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ScrollingView" >
        <attr name="speed" format="integer"/>
        <attr name="src" format="reference"/>
    </declare-styleable>
</resources>

2.在xml中使用自定義的屬性

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:mazhan="http://schemas.android.com/apk/res-auto"
    tools:context="com.mazhan.scrollingview.MainActivity">


    <com.mazhan.scrollingview.ScrollingView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        mazhan:src="@drawable/scrolling_background"
        mazhan:speed="3"/>


</LinearLayout>

3.創(chuàng)建自定義的ScrollingView,在里面繪制bitmap,通過(guò)刷新bitmap的繪制來(lái)提現(xiàn)出動(dòng)畫(huà)效果


public class ScrollingView extends View {
    private int mSpeed;
    private Paint mPaint;
    private Bitmap mBitmap;

    public ScrollingView(Context context) {
        super(context);
    }

    public ScrollingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        // 獲取自定義的屬性值
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScrollingView);

        mSpeed = typedArray.getInteger(R.styleable.ScrollingView_speed, 1);
        int resourceId = typedArray.getResourceId(R.styleable.ScrollingView_src, 0);
        mBitmap = BitmapFactory.decodeResource(getResources(), resourceId);
        typedArray.recycle();

        mPaint = new Paint();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthSize =  MeasureSpec.getSize(widthMeasureSpec);
        setMeasuredDimension(widthSize, mBitmap.getHeight());
    }

    int mOffset = 0;
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //1 畫(huà)圖片

        //節(jié)約效率,避免控件在看不見(jiàn)的地方瘋狂繪制,對(duì)偏移量需要控制
        //負(fù)數(shù)到了一定的范圍,就重置,范圍設(shè)置為bitmap的寬度
        if(mOffset<-mBitmap.getWidth()){
            mOffset = 0;
        }

        //2 填充控件剩下的寬度,多繪制幾個(gè)bitmap上去
        int left = (int) mOffset;
        while (left<getMeasuredWidth()){
//            一直往右邊去繪制,填充
            canvas.drawBitmap(mBitmap,left,0,mPaint);
            left+=mBitmap.getWidth();
        }

        mOffset -= mSpeed;
        //4 讓控件重新繪制
        invalidate();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容