当前位置:首页 > IT技术

横向滑动视图HorizontalScrollView精炼详解

时间:2019-06-29 21:44:28来源:IT技术作者:seo实验室小编阅读:65次「手机版」
 

horizontalscrollview

一、前期基础知识储备

由于移动设备物理显示空间一般有限,不可能一次性的把所有要显示的内容都显示在屏幕上。所以各大平台一般会提供一些可滚动的视图来向用户展示数据Android平台框架中为我们提供了诸如listview、GirdView、SC++rollView、RecyclerView等滚动视图控件,这几个视图控件也是我们平常使用最多的。本节内容我们来分析一下横向滚动视图horizontalscrollview。

HorizontalScrollView是Framelayout的子类,这意味着你只能在它下面放置一个子控件,这个子控件可以包含很多数据内容。有可能这个子控件本身就是一个布局控件,可以包含非常多的其他用来展示数据的控件。这个布局控件一般使用的是一个水平布局的LinearLayout

本节内容使用HorizontalScrollView分为两种情形:

①横向布局视图中放入文字;

②横向布局视图中放入图片

二、上代码,具体实现文字类的横向布局

(1)布局文件

<?xml version="1.0" encoding="utf-8"?>
<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="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.adMinistrator.hscrollview.MainActivity">

    <HorizontalScrollView
        android:id="@+id/horizontalScrollView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#007b12">

        <LinearLayout
            android:id="@+id/horizontalScrollViewItemcontainer"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal" />
    </HorizontalScrollView>

    <TextView
        android:id="@+id/testTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="TextView_Test" />

</RelativeLayout>

(2)主Activity代码文件

public class MainActivity extends APPCompatActivity
{

    private HorizontalScrollView horizontalScrollView;
    private LinearLayout container;
    private String cities[] = new String[]{"London", "Bangkok", "Paris", "Dubai", "Istanbul", "New York",
                                            "Singapore", "Kuala Lumpur", "Hong Kong", "Tokyo", "Barcelona",
                                            "Vienna", "Los Angeles", "Prague", "Rome", "SEOul", "Mumbai", "Jakarta",
                                            "Berlin", "Beijing", "Moscow", "Taipei", "Dublin", "Vancouver"};
    private ArrayList<String> data = new ArrayList<>();
    private TextView testTextView;

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

        bindData();
        setUIRef();
        bindHZSWData();
    }
	//将集合中的数据绑定到HorizontalScrollView上
    private void bindHZSWData()
    {	//为布局中textview设置好相关属性
        LinearLayout.layoutparams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 
		ViewGroup.LayoutParams.WRAP_CONTENT);
        layoutParams.gravity = Gravity.CENTER;
        layoutParams.setMargins(20, 10, 20, 10);

        for (int i = 0; i < data.size(); i++)
        {
            TextView textView = new TextView(this);
            textView.setText(data.get(i));
            textView.setTextcolor(Color.WHITE);
            textView.setLayoutParams(layoutParams);
            container.addView(textView);  
            container.invalidate();  
        }
    }

	//初始化布局中的控件
    private void setUIRef()
    {
        horizontalScrollView = (HorizontalScrollView) findViewById(R.id.horizontalScrollView);
        container = (LinearLayout) findViewById(R.id.horizontalScrollViewItemContainer);
        testTextView = (TextView) findViewById(R.id.testTextView);
    }
	//将字符串数组与集合绑定起来
    private void bindData()
    {
        //add all cities to our ArrayList
        Collections.addAll(data, cities);
    }

}

运行效果如图:

(3)为HorizontalScrollView中的item设置点击事件

在上面的代码中添加两段代码

    private void bindHZSWData() {
		....
		....
        for (int i = 0; i < data.size(); i++) {
            TextView textView = new TextView(this);
            textView.setText(data.get(i));
            textView.setTextColor(Color.WHITE);
            textView.setLayoutParams(layoutParams);

            textView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    performItemClick(view);
                }
            });
		....
        }
    }
    private void performItemClick(View view) {
        //------get display's Width--------
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

        int screenWidth = displayMetrics.widthPixels;

        int scrollX = (view.getLeft() - (screenWidth / 2)) + (view.getWidth() / 2);

        //smooth scrolling horizontalScrollView
        horizontalScrollView.smoothScrollTo(scrollX, 0);

        //additionally we set current center textView data to our testTextView
        String s = "CenterLocked Item: "+((TextView)view).getText();
        testTextView.setText(s);
    }

为了展示显示效果,将每次item中的text设置到界面中,进行显示,运行效果如图:

三、上代码,具体实现图片类的横向布局

(1)主布局文件

<?xml version="1.0" encoding="utf-8"?>
<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="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.administrator.hscrollview.MainActivity">

    <HorizontalScrollView
        android:id="@+id/horizontalScrollView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#007b12">

        <LinearLayout
            android:id="@+id/horizontalScrollViewItemContainer"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal" />
    </HorizontalScrollView>
</RelativeLayout>

(2)主Activity代码

public class MainActivity extends AppCompatActivity {

    private HorizontalScrollView horizontalScrollView;
    private LinearLayout container;
    private integer mImgIds[] = new Integer[]{R.drawable.aa, R.drawable.bb, R.drawable.cc, R.drawable.dd,
            R.drawable.ee, R.drawable.ff, R.drawable.gg, R.drawable.hh, R.drawable.ii, R.drawable.aaa,
            R.drawable.bbb, R.drawable.ccc, R.drawable.ddd,
            R.drawable.eee, R.drawable.fff, R.drawable.ggg, R.drawable.hhh, R.drawable.iii};


    private ArrayList<Integer> data = new ArrayList<>();


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

        bindData();
        setUIRef();
        bindHZSWData();
    }

    private void bindHZSWData() {
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        layoutParams.gravity = Gravity.CENTER;
        layoutParams.setMargins(20, 10, 20, 10);

        for (int i = 0; i < data.size(); i++) {
            ImageView imageView = new ImageView(this);
            imageView.setImageResource(data.get(i));
            imageView.setLayoutParams(layoutParams);

            container.addView(imageView);
            container.invalidate();
        }
    }

    //初始化布局中定义的控件
    private void setUIRef() {
        horizontalScrollView = (HorizontalScrollView) findViewById(R.id.horizontalScrollView);
        container = (LinearLayout) findViewById(R.id.horizontalScrollViewItemContainer);
        testTextView = (TextView) findViewById(R.id.testTextView);
    }

    //将字符串数组中的数据加入到集合当中
    private void bindData() {
        //add all cities to our ArrayList
        Collections.addAll(data, mImgIds);
    }
}

运行效果如图:

当然了,最简单的运用图片类的HorizontalScrollView,就是直接将图片放置在HorizontalScrollView的子布局中进行显示,只需要一个布局文件进行控制,这样做非常简单,UI是通过布局文件进行控制。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.administrator.horizontalscrollview.MainActivity">

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <ImageView
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:background="#ff00ff" />

            <ImageView
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:background="#000000" />

            <ImageView
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:background="#b7a500" />

            <ImageView
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:background="#c1070e" />

            <ImageView
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:background="#ff00ff" />

            <ImageView
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:background="#000000" />

            <ImageView
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:background="#b7a500" />

            <ImageView
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:background="#c1070e" />

        </LinearLayout>
    </HorizontalScrollView>
</RelativeLayout>

注意:无论使用何种方式,注意HoriztalScrollview都只有一个直接子view。否则会报错:

Caused by: java.lang.IllegalStateException: HorizontalScrollView can host only one direct child

三、HorizontalScrollView添加自动滚动和回弹效果

1)添加自动滚动效果

HorizontalScrollView并没有内置自动滚动的API方法,所以要自己实现,滚动类似平移,所以采用平移动画实现。

private AnimatorSet mAnimatorSetLeft, mAnimatorSetRight;
private ObjectAnimator mItemsliding;
private ObjectAnimator mItemsAlpha;

    //初始化布局中的控件
    private void setUIRef() {
        horizontalScrollView = (HorizontalScrollView) findViewById(R.id.horizontalScrollView);
        UITools.elasticPadding(horizontalScrollView, 300);
        //container 为HorizontalScrollView的直接子布局
        container = (LinearLayout) findViewById(R.id.horizontalScrollViewItemContainer);

        mAnimatorSetLeft = new AnimatorSet();
        mAnimatorSetRight = new AnimatorSet();
        mItemsliding = ObjectAnimator.ofFloat(container,"translationX",0,-600);
        mItemsAlpha = ObjectAnimator.ofFloat(container,"alpha",0,0);
        mAnimatorSetLeft.setDuration(0);
        mAnimatorSetLeft.play(mItemsliding).with(mItemsAlpha);
        mAnimatorSetLeft.start();
        mAnimatorSetLeft.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mItemsliding = ObjectAnimator.ofFloat(container,"translationX",-600,0);
                mItemsAlpha = ObjectAnimator.ofFloat(container,"alpha",1,1);
                mAnimatorSetRight.setStartDelay(200);
                mAnimatorSetRight.setDuration(1000);
                mAnimatorSetRight.play(mItemsliding).with(mItemsAlpha);
                mAnimatorSetRight.start();
            }
        });

        testTextView = (TextView) findViewById(R.id.testTextView);
    }

注意,这里的动画绑定对象不是HoriztalScrollView而是其直接子布局对象container。

效果如下:

2)添加回弹效果

HorizontalScrollView添加回弹效果,有两种方案:①自定义HorizontalScrollView;②使用工具类;

①自定义HorizontalScrollView,使用时直接作为布局元素替换掉旧的HorizontalScrollView即可;

public class BouncyHScrollView extends HorizontalScrollView {

    private static final int MAX_X_OVERSCROLL_distance = 200;
    private Context mContext;
    private int mMaxXOverscrollDistance;

    public BouncyHScrollView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        mContext = context;
        initBounceDistance();
    }
    public BouncyHScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        mContext = context;
        initBounceDistance();
    }
    public BouncyHScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
        mContext = context;
        initBounceDistance();
    }

    private void initBounceDistance(){
        final DisplayMetrics metrics = mContext.getresources().getDisplayMetrics();
        mMaxXOverscrollDistance = (int) (metrics.density * MAX_X_OVERSCROLL_DISTANCE);
    }

    @Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent){
        //这块是关键性代码
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, mMaxXOverscrollDistance, maxOverScrollY, isTouchEvent);
    }

}

工具类;调用代码

public class UITools {

    /**HorizontalScrollView添加阻尼效果
     * ScrollView效果不太好
     * 利用父元素的Padding给ScrollView添加弹性
     * @param scrollView
     * @param padding
     */
    public static void elasticPadding(final ScrollView scrollView, final int padding){
        View child = scrollView.getChildAt(0);
        //记录以前的padding
        final int oldpt = child.getPaddingTop();
        final int oldpb = child.getPaddingBottom();
        //设置新的padding
        child.setPadding(child.getPaddingLeft(), padding+oldpt, child.getPaddingRight(), padding+oldpb);

        //添加视图布局完成事件监听
        scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            private boolean inTouch = false; //手指是否按下状态

            @SuppressLint("NewApi")
            private void disableOverScroll(){
                scrollView.setOverScrollMode(ScrollView.OVER_SCROLL_NEVER);
            }

            /**  滚动到顶部 */
            private void scrollToTop(){
                scrollView.smoothScrollTo(scrollView.getScrollX(), padding-oldpt);
            }

            /** 滚动到底部 */
            private void scrollToBottom(){
                scrollView.smoothScrollTo(scrollView.getScrollX(), scrollView.getChildAt(0).getBottom()-scrollView.getmeasuredHeight()-padding+oldpb);
            }

            /** 检测scrollView结束以后,复原位置 */
            private final Runnable checkStopped = new Runnable() {
                @Override
                public void run() {
                    int y = scrollView.getScrollY();
                    int bottom = scrollView.getChildAt(0).getBottom()-y-scrollView.getMeasuredHeight();
                    if(y <= padding && !inTouch){
                        scrollToTop();
                    }else if(bottom<=padding && !inTouch){
                        scrollToBottom();
                    }
                }
            };

            @SuppressWarnings("deprecation")
            @Override
            public void onGlobalLayout() {
                //移除监听器
                scrollView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                //设置最小高度
                //scrollView.getChildAt(0).setMinimumHeight(scrollView.getMeasuredHeight());
                //取消overScroll效果
                if(build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD){
                    disableOverScroll();
                }

                scrollView.setOnTouchListener(new OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, motionevent event) {
                        if(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_POINTER_DOWN){
                            inTouch = true;
                        }else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL){
                            inTouch = false;
                            //手指弹起以后检测一次是否需要复原位置
                            scrollView.post(checkStopped);
                        }
                        return false;
                    }
                });

                scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
                    @Override
                    public void onScrollChanged() {
                        if(!inTouch && scrollView!=null && scrollView.gethandler()!=null){//如果持续滚动,移除checkStopped,停止滚动以后只执行一次检测任务
                            scrollView.getHandler().removeCallbacks(checkStopped);
                            scrollView.postDelayed(checkStopped, 100);
                        }
                    }
                });

                //第一次加载视图,复原位置
                scrollView.postDelayed(checkStopped, 300);
            }
        });
    }

    /**
     * 利用父元素的Padding给HorizontalScrollView添加弹性
     * @param scrollView
     * @param padding
     */
    public static void elasticPadding(final HorizontalScrollView scrollView, final int padding){
        Log.i("", "elasticPadding>>>>!!");
        View child = scrollView.getChildAt(0);

        //记录以前的padding
        final int oldpt = child.getPaddingTop();
        final int oldpb = child.getPaddingBottom();
        //设置新的padding
        child.setPadding(padding+oldpt, child.getPaddingTop(), padding+oldpb, child.getPaddingBottom());

        //添加视图布局完成事件监听
        scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            private boolean inTouch = false; //手指是否按下状态

            @SuppressLint("NewApi")
            private void disableOverScroll(){
                scrollView.setOverScrollMode(ScrollView.OVER_SCROLL_NEVER);
            }

            /**  滚动到左边 */
            private void scrollToLeft(){
                scrollView.smoothScrollTo(padding-oldpt, scrollView.getScrollY());
            }

            /** 滚动到底部 */
            private void scrollToRight(){
                scrollView.smoothScrollTo(scrollView.getChildAt(0).getRight()-scrollView.getMeasuredWidth()-padding+oldpb, scrollView.getScrollY());
            }

            /** 检测scrollView结束以后,复原位置 */
            private final Runnable checkStopped = new Runnable() {
                @Override
                public void run() {
                    int x = scrollView.getScrollX();
                    int bottom = scrollView.getChildAt(0).getRight()-x-scrollView.getMeasuredWidth();
                    if(x <= padding && !inTouch){
                        scrollToLeft();
                    }else if(bottom<=padding && !inTouch){
                        scrollToRight();
                    }
                }
            };

            @SuppressWarnings("deprecation")
            @Override
            public void onGlobalLayout() {
                //移除监听器
                scrollView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

                //取消overScroll效果
                if(Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD){
                    disableOverScroll();
                }

                scrollView.setOnTouchListener(new OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        if(event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_POINTER_DOWN){
                            inTouch = true;
                        }else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL){
                            inTouch = false;
                            //手指弹起以后检测一次是否需要复原位置
                            scrollView.post(checkStopped);
                        }
                        return false;
                    }
                });

                scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
                    @Override
                    public void onScrollChanged() {
                        //如果持续滚动,移除checkStopped,停止滚动以后只执行一次检测任务
                        if(!inTouch && scrollView!=null && scrollView.getHandler()!=null){
                            scrollView.getHandler().removeCallbacks(checkStopped);
                            scrollView.postDelayed(checkStopped, 100);
                        }
                    }
                });

                //第一次加载视图,复原位置
                scrollView.postDelayed(checkStopped, 300);
            }
        });
    }
}

调用代码:

UITools.elasticPadding(horizontalScrollView, 200);

传入HorizontalScrollView对象和一个int类型(表示回弹的距离)的数值即可.

效果如下:

最后补充两个HorizontalScrollView的滚动方法:

HorizontalScrollView属于Scroll类家族成员,自然少不了控制其滚动的方法:

①滚动到指定位置 —— smoothScrollTo (intx, inty);

②滚动指定距离 —— smoothScrollBy (intx, inty);

2019.04.21添加:HorizontalScrollView点击子项自动居中的实现,利用smoothScrollTo ()方法实现:

public class HorCenterActivity extends AppCompatActivity implements View.OnClickListener {

    private HorizontalScrollView hor;
    private LinearLayout ll;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hor);
        hor = findViewById(R.id.hor);
        ll = findViewById(R.id.ll);
        for (int i = 0; i < ll.getChildCount(); i++) {
            ll.getChildAt(i).setOnClickListener(this);
        }
    }

    // 实现Horizon自动滚动居中
    private void autoScroll(int i) {
        // Width of the screen
        DisplayMetrics metrics = getResources()
                .getDisplayMetrics();
        int widthScreen = metrics.widthPixels;

        // Width of one child (Button)
        int widthChild = ll.getChildAt(i).getWidth(); // 获取对应位置的子View的宽度

        // Nb children in screen
        int nbChildInScreen = widthScreen / widthChild;

        // Child position left
        int positionLeftChild = ll.getChildAt(i).getLeft(); // 获取对应位置的子View的左边位置 - 坐标

        // Auto scroll to the middle
        hor.smoothScrollTo((positionLeftChild - ((nbChildInScreen * widthChild) / 2) + widthChild / 2), 0);
//        hor.smoothScrollTo((positionLeftChild - (widthScreen / 2) + widthChild / 2), 0);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.a:
                autoScroll(0);
                break;
            case R.id.aa:
                autoScroll(1);
                break;
            case R.id.aaa:
                autoScroll(2);
                break;
            case R.id.aaaa:
                autoScroll(3);
                break;
            case R.id.aaaaa:
                autoScroll(4);
                break;
            case R.id.aaaaaa:
                autoScroll(5);
                break;
            case R.id.aaaaaaa:
                autoScroll(6);
                break;
            case R.id.aaaaaaaa:
                autoScroll(7);
                break;
        }
    }
}

如上autoScroll()方法,我们传入子项的索引值即可,从0开始,注意,此实现方式不论子项是否可见,索引值都是不变的,比如一共有7个子项,索引值是0~6,然后将前三个子项设为不可见,此时所有子项的索引值仍然是0~6,而不会有所变化。

效果如下:

相关阅读

JavaScript窗体Window.ShowModalDialog使用详解

Javascript有许多内建的方法来产生对话框,如:window.alert(), window.confirm(),window.prompt().等。 然而IE提供更多的方法支持对

Linux中挂载详解以及mount命令用法

挂载概念Linux中的根目录以外的文件要想被访问,需要将其“关联”到根目录下的某个目录来实现,这种关联操作就是“挂载”,这个目录就

java集合详解

Java容器可分为两大类:CollectionListArrayListLinkedListVector(了解,已过时)SetHashSetLinkedHashSetTreeSetMapHashMapLinkedHas

Maven中标签详解

Maven中< resources>标签详解 clean install -DskipTests -P test 传入test参数 DskipTests,不执行测试用例 -P test 会

Windows原生MPIO存储多路径软件详解与应用

Windows原生MPIO存储多路径软件详解与应用  介绍在Windows Server 2008和Windows Server 2008 R2中开始支持Native Multipathing

分享到:

栏目导航

推荐阅读

热门阅读