• android123 zhihuibeijing 新闻中心-新闻 页签 ViewPagerIndicator实现


    ## ViewPagerIndicator ##  使用导入ViewPagerIndicator库的方式相当于可以改源码,打包编译Eclips可以自动完成。
    
    ViewPager指针项目,在使用ViewPager的时候能够指示ViewPager所在的位置,就像Google Play中切换的效果一样,还能使用在应用初始化的介绍页面
    
    1. 引入ViewPagerIndicator库
    2. 编写布局文件
    
             <com.viewpagerindicator.TabPageIndicator
            android:id="@+id/indicator"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    
    3. mIndicator.setViewPager(mViewPager);//将viewpager和mIndicator关联起来,必须在viewpager设置完adapter后才能调用
    
    4. 重写PagerAdapter方法,返回页面标题
    
            /**
             * 重写此方法,返回页面标题,用于viewpagerIndicator的页签显示
             */
            @Override
            public CharSequence getPageTitle(int position) {
                return mNewsTabData.get(position).title;
            }
    
    5. 自定义样式修改
    清单文件:
     <activity
        android:name=".MainActivity"
        android:theme="@style/Theme.PageIndicatorDefaults" />
    然后修改Theme.PageIndicatorDefaults这个样式文件。
    package com.itheima.zhbj52.base.menudetail;
    
    import java.util.ArrayList;
    
    import android.app.Activity;
    import android.support.v4.view.PagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.support.v4.view.ViewPager.OnPageChangeListener;
    import android.view.View;
    import android.view.ViewGroup;
    
    import com.itheima.zhbj52.MainActivity;
    import com.itheima.zhbj52.R;
    import com.itheima.zhbj52.base.BaseMenuDetailPager;
    import com.itheima.zhbj52.base.TabDetailPager;
    import com.itheima.zhbj52.domain.NewsData.NewsTabData;
    import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
    import com.lidroid.xutils.ViewUtils;
    import com.lidroid.xutils.view.annotation.event.OnClick;
    import com.viewpagerindicator.TabPageIndicator;
    
    /**
     * 新闻中心-新闻
     */
    public class NewsMenuDetailPager extends BaseMenuDetailPager implements OnPageChangeListener {
        /*public abstract class BaseMenuDetailPager {
            public Activity mActivity;
            public View mRootView;
            public BaseMenuDetailPager(Activity activity) {
                mActivity = activity;
                mRootView = initViews();
            }
            public abstract View initViews();
            public void initData() {
            }
        }*/
        private ViewPager mViewPager;//11个标签页的适配器
        private ArrayList<TabDetailPager> mPagerList;//11个标签页
        private ArrayList<NewsTabData> mNewsTabData;// 页签网络数据
        private TabPageIndicator mIndicator;//viewpagerindicator实现的标签头
    
        public NewsMenuDetailPager(Activity activity,ArrayList<NewsTabData> children) {
            super(activity);
            mNewsTabData = children;
        }
    
        @Override
        public View initViews() {
            View view = View.inflate(mActivity, R.layout.news_menu_detail, null);//返回给上层flContent的页面View对象。
            /*<?xml version="1.0" encoding="utf-8"?>
            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical" >
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal" >
                    <com.viewpagerindicator.TabPageIndicator    ViewPager页标签的固定写法
                        android:id="@+id/indicator"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_weight="1" />
                    <ImageButton     可以切换页标签的按钮
                        android:id="@+id/btn_next"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_vertical"
                        android:background="@android:color/transparent"
                        android:padding="5dp"
                        android:src="@drawable/news_cate_arr"    图片/> 
                </LinearLayout>
                <android.support.v4.view.ViewPager
                    android:id="@+id/vp_menu_detail"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </LinearLayout>*/
            mViewPager = (ViewPager) view.findViewById(R.id.vp_menu_detail);
            ViewUtils.inject(this, view);
            mIndicator = (TabPageIndicator) view.findViewById(R.id.indicator);
            // mViewPager.setOnPageChangeListener(this);//注意:当viewpager和Indicator绑定时,
            // 滑动监听需要设置给Indicator而不是viewpager,这样滑动viewpager的时候上面的标签就能够跟着下面的viewpager一起滑动。
            mIndicator.setOnPageChangeListener(this);
            return view;
        }
    
        @Override
        public void initData() {
            mPagerList = new ArrayList<TabDetailPager>();
            // 初始化页签数据
            for (int i = 0; i < mNewsTabData.size(); i++) {
                TabDetailPager pager = new TabDetailPager(mActivity,
                        mNewsTabData.get(i));
                mPagerList.add(pager);
            }
            mViewPager.setAdapter(new MenuDetailAdapter());
            mIndicator.setViewPager(mViewPager);// 将viewpager和mIndicator关联起来,这样每个ViewPager就有标签头了,必须在viewpager设置完adapter后才能调用
        }
    
        // 按钮的监听事件
        @OnClick(R.id.btn_next)
        public void nextPage(View view) {
            int currentItem = mViewPager.getCurrentItem();
            mViewPager.setCurrentItem(++currentItem);
        }
    
        class MenuDetailAdapter extends PagerAdapter {
             //重写此方法,返回页面标题,用于viewpagerIndicator的页签显示
            @Override
            public CharSequence getPageTitle(int position) {
                return mNewsTabData.get(position).title;
            }
    
            @Override
            public int getCount() {
                return mPagerList.size();
            }
    
            @Override
            public boolean isViewFromObject(View arg0, Object arg1) {
                return arg0 == arg1;
            }
    
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                TabDetailPager pager = mPagerList.get(position);//新闻的11个子页面
                container.addView(pager.mRootView);
                pager.initData();
                return pager.mRootView;
            }
    
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView((View) object);
            }
        }
    
        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
    
        }
    
        @Override
        public void onPageSelected(int arg0) {
            System.out.println("onPageSelected:" + arg0);
    
            MainActivity mainUi = (MainActivity) mActivity;
            SlidingMenu slidingMenu = mainUi.getSlidingMenu();
    
            if (arg0 == 0) {//只有在第一个页面(北京), 侧边栏才允许出来
                slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
            } else {
                slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE);
            }
        }
    
    }

     自定义ViewPager处理事件的拦截:

    package com.itheima.zhbj52.view;
    
    import android.content.Context;
    import android.support.v4.view.ViewPager;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    
    /**
     * 头条新闻的Viewpager
     */
    public class TopNewsViewPager extends ViewPager {
        int startX;
        int startY;
        public TopNewsViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        public TopNewsViewPager(Context context) {
            super(context);
        }
        /**
         * ViewPager嵌套的时候,父子的滑动事件处理:
         * 事件分发, 请求父控件及祖宗控件是否拦截事件,请求父控件及祖宗控件不要拦截则事件就可以传到这个控件来,dispatchTouchEvent()方法里面重写。
         *  1. 右划, 而且是第一个页面, 需要父控件拦截 ,此时父控件可以滑动。
         *  2. 左划, 而且是最后一个页面, 需要父控件拦截 ,此时父控件可以滑动。
         * 3. 上下滑动, 需要父控件拦截
         */
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                getParent().requestDisallowInterceptTouchEvent(true);// 请求父控件不要拦截,所有的父控件都不拦截。
                startX = (int) ev.getRawX();
                startY = (int) ev.getRawY();//.getX()是获取基于父控件的位置,getRawX()是获取基于屏幕的位置。
                break;
            case MotionEvent.ACTION_MOVE:
                int endX = (int) ev.getRawX();
                int endY = (int) ev.getRawY();
                if (Math.abs(endX - startX) > Math.abs(endY - startY)) {// 左右滑动
                    if (endX > startX) {// 右划
                        if (getCurrentItem() == 0) {// 第一个页面, 需要父控件拦截
                            getParent().requestDisallowInterceptTouchEvent(false);
                        }
                    } else {// 左划
                        if (getCurrentItem() == getAdapter().getCount() - 1) {// 最后一个页面,
                                                                                // 需要拦截
                            getParent().requestDisallowInterceptTouchEvent(false);
                        }
                    }
                } else {// 上下滑动
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            default:
                break;
            }
            return super.dispatchTouchEvent(ev);
        }
    }

    package com.itheima.zhbj52.base;
    
    import java.util.ArrayList;
    
    import android.app.Activity;
    import android.support.v4.view.PagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.support.v4.view.ViewPager.OnPageChangeListener;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.ImageView.ScaleType;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.google.gson.Gson;
    import com.itheima.zhbj52.R;
    import com.itheima.zhbj52.domain.NewsData.NewsTabData;
    import com.itheima.zhbj52.domain.TabData;
    import com.itheima.zhbj52.domain.TabData.TabNewsData;
    import com.itheima.zhbj52.domain.TabData.TopNewsData;
    import com.itheima.zhbj52.global.GlobalContants;
    import com.itheima.zhbj52.view.RefreshListView;
    import com.lidroid.xutils.BitmapUtils;
    import com.lidroid.xutils.HttpUtils;
    import com.lidroid.xutils.ViewUtils;
    import com.lidroid.xutils.exception.HttpException;
    import com.lidroid.xutils.http.ResponseInfo;
    import com.lidroid.xutils.http.callback.RequestCallBack;
    import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;
    import com.lidroid.xutils.view.annotation.ViewInject;
    import com.viewpagerindicator.CirclePageIndicator;
    
    /**
     * 新闻中心-新闻-北京  页签详情页
     */
    public class TabDetailPager extends BaseMenuDetailPager implements OnPageChangeListener {
    
        NewsTabData mTabData;
        private TextView tvText;
    
        private String mUrl;
        private TabData mTabDetailData;
    
        @ViewInject(R.id.vp_news)
        private ViewPager mViewPager;
    
        @ViewInject(R.id.tv_title)
        private TextView tvTitle;// 头条新闻的标题
        private ArrayList<TopNewsData> mTopNewsList;// 头条新闻数据集合
    
        @ViewInject(R.id.indicator)
        private CirclePageIndicator mIndicator;// 头条新闻位置指示器,安卓自带的(4个黑色的指示位置的圆点,还支持点击)
    
        @ViewInject(R.id.lv_list)
        private RefreshListView lvList;// 新闻列表
        private ArrayList<TabNewsData> mNewsList; // 新闻数据集合
        private NewsAdapter mNewsAdapter;
    
        public TabDetailPager(Activity activity, NewsTabData newsTabData) {
            super(activity);
            mTabData = newsTabData;
            mUrl = GlobalContants.SERVER_URL + mTabData.url;
        }
    
        @Override
        public View initViews() {
            View view = View.inflate(mActivity, R.layout.tab_detail_pager, null);
            //tab_detail_pager.xml
            /*<?xml version="1.0" encoding="utf-8"?>
            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical" >
                <com.itheima.zhbj52.view.RefreshListView    下拉刷新的文字和箭头部分,这也是一个ListView。
                    android:id="@+id/lv_list"
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:cacheColorHint="#fff"
                    android:layout_weight="1" >
                </com.itheima.zhbj52.view.RefreshListView>
            </LinearLayout>*/
            // 加载头布局(图片滑动的viewPaer),整体作为一个头view加载进ListView(下面的滑动新闻列表),这样headerView就会在listView里面一起滑动。
            View headerView = View.inflate(mActivity, R.layout.list_header_topnews,null);
            //list_header_topnews.xml
            /*<?xml version="1.0" encoding="utf-8"?>
            <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" >
                <com.itheima.zhbj52.view.TopNewsViewPager
                    android:id="@+id/vp_news"
                    android:layout_width="match_parent"
                    android:layout_height="200dp" />
                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_alignParentBottom="true"
                    android:background="#a000"
                    android:padding="3dp" >
                    <TextView
                        android:id="@+id/tv_title"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textColor="#fff"
                        android:textSize="16sp" /> 
                    <com.viewpagerindicator.CirclePageIndicator       安卓自带的(4个黑色的指示位置的圆点,还支持点击)
                        android:id="@+id/indicator" 
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentRight="true"
                        android:padding="10dip"
                        app:fillColor="#f00"
                        app:pageColor="@android:color/darker_gray"
                        app:radius="3dp"
                        app:strokeWidth="0dp" />
                </RelativeLayout>
            </RelativeLayout>*/
    
            ViewUtils.inject(this, view);//view里面的控件就可以支持注解了。
            ViewUtils.inject(this, headerView);//headerView里面的控件就可以支持注解了。
    
            // 将头条新闻以头布局的形式加给listview
            lvList.addHeaderView(headerView);//后加载的HeaderView在下面。
            return view;
        }
    
        @Override
        public void initData() {
            getDataFromServer();
        }
    
        private void getDataFromServer() {
            HttpUtils utils = new HttpUtils();
            utils.send(HttpMethod.GET, mUrl, new RequestCallBack<String>() {
    
                @Override
                public void onSuccess(ResponseInfo<String> responseInfo) {
                    String result = (String) responseInfo.result;
                    System.out.println("页签详情页返回结果:" + result);
    
                    parseData(result);
                }
    
                @Override
                public void onFailure(HttpException error, String msg) {
                    Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
                    error.printStackTrace();
                }
            });
        }
    
        protected void parseData(String result) {
            Gson gson = new Gson();
            mTabDetailData = gson.fromJson(result, TabData.class);
            System.out.println("页签详情解析:" + mTabDetailData);
    
            mTopNewsList = mTabDetailData.data.topnews;
    
            mNewsList = mTabDetailData.data.news;
    
            if (mTopNewsList != null) {
                mViewPager.setAdapter(new TopNewsAdapter());
                mIndicator.setViewPager(mViewPager);
                mIndicator.setSnap(true);// 支持快照显示
                mIndicator.setOnPageChangeListener(this);
    
                mIndicator.onPageSelected(0);// 让指示器重新定位到第一个点
    
                tvTitle.setText(mTopNewsList.get(0).title);
            }
    
            if (mNewsList != null) {
                mNewsAdapter = new NewsAdapter();
                lvList.setAdapter(mNewsAdapter);
            }
        }
    
        /**
         * 头条新闻适配器,ViewPager的适配器
         */
        class TopNewsAdapter extends PagerAdapter {
    
            private BitmapUtils utils;
    
            public TopNewsAdapter() {
                utils = new BitmapUtils(mActivity);
                utils.configDefaultLoadingImage(R.drawable.topnews_item_default);// 设置默认图片,下载图片的时候要等待,等待的时候显示这个图片。
            }
    
            @Override
            public int getCount() {
                return mTabDetailData.data.topnews.size();
            }
    
            @Override
            public boolean isViewFromObject(View arg0, Object arg1) {
                return arg0 == arg1;
            }
    
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                ImageView image = new ImageView(mActivity);
                image.setScaleType(ScaleType.FIT_XY);// 基于控件大小填充图片
    
                TopNewsData topNewsData = mTopNewsList.get(position);
                utils.display(image, topNewsData.topimage);// 传递imagView对象和图片地址,从url加载图片。图片多了就会内存溢出。
    
                container.addView(image);
                
                System.out.println("instantiateItem....." + position);
                return image;
            }
    
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView((View) object);
            }
        }
    
        /**
         * 新闻列表的适配器,ListView的适配器。
         */
        class NewsAdapter extends BaseAdapter {
    
            private BitmapUtils utils;
    
            public NewsAdapter() {
                utils = new BitmapUtils(mActivity);
                utils.configDefaultLoadingImage(R.drawable.pic_item_list_default);//设置默认的图片
            }
    
            @Override
            public int getCount() {
                return mNewsList.size();
            }
    
            @Override
            public TabNewsData getItem(int position) {
                return mNewsList.get(position);
            }
    
            @Override
            public long getItemId(int position) {
                return position;
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder holder;
                if (convertView == null) {
                    convertView = View.inflate(mActivity, R.layout.list_news_item,null);
                    //list_news_item.xml
                    /*<?xml version="1.0" encoding="utf-8"?>
                    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content" 
                        android:padding="10dp"
                        >
                        <ImageView
                            android:id="@+id/iv_pic"
                            android:layout_width="110dp"    图片大小写死
                            android:layout_height="70dp"
                            android:scaleType="fitXY"       小了的话填满
                            android:padding="1dp"
                            android:background="@android:color/darker_gray"   背景是黑颜色,并且设置padding=1dp,这样就实现了图片周围有黑框。
                            android:layout_alignParentLeft="true"
                            android:layout_alignParentTop="true"
                            android:src="@drawable/image_demo" />
                        <TextView
                            android:id="@+id/tv_title"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentTop="true"
                            android:layout_marginLeft="20dp"
                            android:layout_toRightOf="@+id/iv_pic"
                            android:text="新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题"
                            android:textColor="#000"
                            android:maxLines="2"
                            android:ellipsize="end"     多余文字在末尾加......
                            android:textSize="20sp" />
                        <TextView
                            android:id="@+id/tv_date"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignLeft="@id/tv_title"
                            android:text="2015-03-16 16:20"
                            android:layout_alignBottom="@id/iv_pic"
                            android:textColor="@android:color/darker_gray"
                            android:textSize="16sp" />
                    </RelativeLayout>*/
                    holder = new ViewHolder();
                    holder.ivPic = (ImageView) convertView.findViewById(R.id.iv_pic);
                    holder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
                    holder.tvDate = (TextView) convertView.findViewById(R.id.tv_date);
    
                    convertView.setTag(holder);
                } else {
                    holder = (ViewHolder) convertView.getTag();
                }
    
                TabNewsData item = getItem(position);
    
                holder.tvTitle.setText(item.title);
                holder.tvDate.setText(item.pubdate);
    
                utils.display(holder.ivPic, item.listimage);
    
                return convertView;
            }
    
        }
    
        static class ViewHolder {
            public TextView tvTitle;
            public TextView tvDate;
            public ImageView ivPic;
        }
    
        @Override
        public void onPageScrollStateChanged(int arg0) {
    
        }
    
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
    
        }
    
        @Override
        public void onPageSelected(int arg0) {
            TopNewsData topNewsData = mTopNewsList.get(arg0);
            tvTitle.setText(topNewsData.title);
        }
    }
    package com.itheima.zhbj52.view;
    
    import com.itheima.zhbj52.R;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.View;
    import android.widget.ListView;
    
    /**
     * 下拉刷新的ListView
     */
    public class RefreshListView extends ListView {
    
        private View mHeaderView;
    
        public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            initHeaderView();
        }
    
        public RefreshListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initHeaderView();
        }
    
        public RefreshListView(Context context) {
            super(context);
            initHeaderView();
        }
    
        /**
         * 初始化头布局
         */
        private void initHeaderView() {
            mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);
            //refresh_header.xml
            /*<?xml version="1.0" encoding="utf-8"?>
            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal" >
                <FrameLayout                                帧布局,叠加在一起
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingLeft="10dp"
                    android:paddingRight="10dp"
                    android:paddingTop="10dp" >
                    <ImageView
                        android:id="@+id/iv_arr"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center"
                        android:src="@drawable/common_listview_headview_red_arrow" />   向下箭头
                    <ProgressBar                            转圈的进度条
                        android:id="@+id/pb_progress"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center"
                        android:visibility="invisible" />
                </FrameLayout>
                    箭头旁边的文字
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout_gravity="center"
                    android:gravity="center"
                    android:orientation="vertical" >
                    <TextView
                        android:id="@+id/tv_title"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="下拉刷新"
                        android:textColor="#f00"
                        android:textSize="20sp" />
                    <TextView
                        android:id="@+id/tv_time"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="2015-03-10 17:07:07"
                        android:textColor="@android:color/darker_gray"
                        android:textSize="16sp" />
                </LinearLayout>
            </LinearLayout>*/
            this.addHeaderView(mHeaderView);//listView加多个HeaderView的时候,先加的在上面。
    
            mHeaderView.measure(0, 0);
            int mHeaderViewHeight = mHeaderView.getMeasuredHeight();
    
            mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);//隐藏头布局
        }
    }
  • 相关阅读:
    研究显示:众多网上零售商未遵循Web优化基本准则
    坚果云开发团队分享高效代码审查经验
    不应忽视的HTML优化
    开源网络分析工具TCP Traffic Analyzer
    Web 2.0应用客户端性能问题十大根源
    W3C宣布成立Web性能工作组
    Google C++规范
    Yahoo推出开源YUI跨浏览器测试工具Yeti
    比较牛的一个字符画
    python调用windows下的应用程序的方法
  • 原文地址:https://www.cnblogs.com/yaowen/p/5052789.html
Copyright © 2020-2023  润新知