Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 仿今日頭條和qq側滑和智慧北京的小項目 3

仿今日頭條和qq側滑和智慧北京的小項目 3

編輯:關於Android編程

本項目圖片素材均來自今日頭條,QQ側滑沒有使用Android原生的NavigationDrawer,而使用的是第三方SlidingMenu,原因是這個控件暫時沒有仔細研究(後期會研究並寫demo),項目整體可以說是使用了一個Activity加多個Fragment,全部采用沉寂式。

 

TabPager(NewsPager新聞頁面對應的11個子頁面)

這裡寫圖片描述

此頁面相對比較復雜,所以單獨用一篇blog來說明都處理了哪些邏輯

從網絡上獲取json數據

private void getDataFromNet() {
        HttpUtils httpUtils = new HttpUtils();
        httpUtils.send(HttpRequest.HttpMethod.GET, url, new RequestCallBack

解析json數據

解析json數據分為若干部分,解析json、初始化數據、設置數據、處理和解析數據。

解析json(javaBean在此不做贅述,獲取json,直接生成即可)
private TopNewsBean topNewsJson(String result) {
        Gson gson = new Gson();
        TopNewsBean topNewsBean;
        topNewsBean = gson.fromJson(result, TopNewsBean.class);
        return topNewsBean;
    }
初始化數據、設置數據
/**
     * 解析json數據
     *
     * @param result
     */
    private void resolutionJson(String result) {
        TopNewsBean topNewsBean = topNewsJson(result);
        if (!isLoadMore){
            //把解析json封裝成一個方法這樣看起來代碼沒那麼亂
            topNewsList = topNewsBean.getData().getTopnews();

            moreUrl = topNewsBean.getData().getMore();
            if (TextUtils.isEmpty(moreUrl)) {
                moreUrl = null;
            }else {
                moreUrl = ConstantUtils.CONNECTURL+moreUrl;
            }
            //初始化頂部新聞的Viewpager數據

            //初始化Viewpager數據
            TopNewsTabAdapter topNewsTabAdapter = new TopNewsTabAdapter();
//        給ViewPager設置數據
            hvp.setAdapter(topNewsTabAdapter);
            hvp.setOnPageChangeListener(this);

            //初始化文字和點

            llPoint.removeAllViews();//因為訪問網絡讀取緩存這個方法會被執行2此,所以需要要移除以前的view
            View view = null;
            for (int i = 0; i < topNewsList.size(); i++) {
                view = new View(mActivity);
                view.setBackgroundResource(R.drawable.point_seclect);
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(15, 15);
                if (i != 0) {
                    params.leftMargin = 15;
                }
                view.setEnabled(false);
                view.setLayoutParams(params);
                llPoint.addView(view);

            }
            //初始化第一個點和文字
            firstDescription = 0;
            tvTopNewsDes.setText(topNewsList.get(firstDescription).getTitle());
            llPoint.getChildAt(firstDescription).setEnabled(true);


            //初始化listview數據
            newsItem = topNewsBean.getData().getNews();
            listNewsAdapter = new ListNewsAdapter();
            listNews.setAdapter(listNewsAdapter);


            // TODO: 16/5/28    給Viewpager設置自動滑動
            //因為該方法會執行2次,所以需要清空一次
            if (myHandle==null){
                myHandle = new MyHandle();
            }else {
                myHandle.removeCallbacksAndMessages(null);
            }
            myHandle.postDelayed(new MyRunnable(),4000);
        }else {
            isLoadMore = false;
            List moreNewsItem = topNewsBean.getData().getNews();
            newsItem.addAll(moreNewsItem);
            listNewsAdapter.notifyDataSetChanged();
        }
    }
處理和解析數據

1、輪播圖數據

class TopNewsTabAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            return topNewsList.size();
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView imageView = new ImageView(mActivity);

            //給imageview設置事件

            //設置默認圖片和背景拉伸
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            imageView.setBackgroundResource(R.drawable.default_bg);
            bitmapUtils = new BitmapUtils(mActivity);
            // 配置默認圖片的像素單位
            bitmapUtils.configDefaultBitmapConfig(Bitmap.Config.ARGB_4444);
            //topimage的網絡地址
            topNews = topNewsList.get(position);

            /**
             * container 下面的uri參數請求下來的圖片, 設置給container來展示.
             * uri 圖片的請求地址
             */
            bitmapUtils.display(imageView, topNews.getTopimage());
            container.addView(imageView);
            return imageView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

    }

2、列表listview新聞數據

class ListNewsAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return newsItem.size();
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder = null;
            if (convertView == null) {
                convertView = View.inflate(mActivity, R.layout.listnews_item, null);
                viewHolder = new ViewHolder(convertView);
                convertView.setTag(viewHolder);
            }else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            TopNewsBean.DataBean.NewsBean newsBean = newsItem.get(position);
            viewHolder.tvListNews.setText(newsBean.getTitle());
            viewHolder.tvListDate.setText(newsBean.getPubdate());

            // 判斷當前是否是已讀的新聞
            String readableIDArray = CacheUtils.getString(mActivity, READABLE_NEWS_ID_ARRAY_KEY, null);
            // TODO: 16/5/27
            if(!TextUtils.isEmpty(readableIDArray)
                    && readableIDArray.contains(newsBean.getId()+"")) {
                viewHolder.tvListNews.setTextColor(Color.GRAY);
            } else {
                viewHolder.tvListNews.setTextColor(Color.BLACK);
            }

            //設置默認圖片
            viewHolder.ivListNews.setBackgroundResource(R.drawable.listnews_default_bg);
            bitmapUtils.display(viewHolder.ivListNews,newsBean.getListimage());
            return convertView;
        }

         class ViewHolder {
            @Bind(R.id.iv_list_news)
            public ImageView ivListNews;
            @Bind(R.id.tv_list_news)
            public TextView tvListNews;
             @Bind(R.id.tv_list_date)
             public TextView tvListDate;

            ViewHolder(View view) {
                ButterKnife.bind(this, view);
            }
        }
    }

viewpager輪播新聞頁面邏輯

設置點和文字的自動切換、自動輪播

設置點和文字的自動切換

1、給Viewpager設置頁面滑動監聽

2、初始化點和文字描述控件

 //初始化文字和點

 llPoint.removeAllViews();//因為訪問網絡讀取緩存這個方法會被執行2此,所以需要要移除以前的view
            View view = null;
            for (int i = 0; i < topNewsList.size(); i++) {
                view = new View(mActivity);
                view.setBackgroundResource(R.drawable.point_seclect);
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(15, 15);
                if (i != 0) {
                    params.leftMargin = 15;
                }
                view.setEnabled(false);
                view.setLayoutParams(params);
                llPoint.addView(view);

            }
            //初始化第一個點和文字
            firstDescription = 0;
            tvTopNewsDes.setText(topNewsList.get(firstDescription).getTitle());
            llPoint.getChildAt(firstDescription).setEnabled(true);

3、主要實現onPageSelected方法

//Viewpager的滑動事件監聽

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        //設置點的切換
        tvTopNewsDes.setText(topNewsList.get(position).getTitle());
        llPoint.getChildAt(firstDescription).setEnabled(false);
        llPoint.getChildAt(position).setEnabled(true);
        firstDescription = position;
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

自動輪播(通過Handle實現,定時任務)

為什麼執行2次,第一次從緩存中讀取數據,並處理數據,第二次從網絡上獲取數據,並處理數據。

// TODO: 16/5/28    給Viewpager設置自動滑動
            //因為該方法會執行2次,所以需要清空一次
            if (myHandle==null){
                myHandle = new MyHandle();
            }else {
                myHandle.removeCallbacksAndMessages(null);
            }
            myHandle.postDelayed(new MyRunnable(),4000);
        }else {
            isLoadMore = false;
            List moreNewsItem = topNewsBean.getData().getNews();
            newsItem.addAll(moreNewsItem);
            listNewsAdapter.notifyDataSetChanged();
        }

//Handle
class MyHandle extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //用於處理消息
            int newCurrentItem = (hvp.getCurrentItem() + 1)%topNewsList.size();
            hvp.setCurrentItem(newCurrentItem);
            //消息處理完在重新發送,類似遞歸
            myHandle.postDelayed(new MyRunnable(),4000);
        }
    }

  //run方法
class MyRunnable implements Runnable{

        @Override
        public void run() {
            //發一條空的消息
            myHandle.sendEmptyMessage(0);
        }
    }

列表新聞listview頁面邏輯處理(自定義Listview)

下拉刷新、上拉加載

寫一個類繼承自listview,添加自定義頭布局和尾布局,監聽滑動事件等。
以下貼出關鍵代碼。

下拉刷新部分

添加頭布局

/**
     * 添加頭布局
     */
    private void initHeadView() {
        headView = View.inflate(getContext(), R.layout.refresh_headview, null);
        ButterKnife.bind(this, headView);
        this.addHeaderView(headView);
        //默認隱藏頭布局
        headView.measure(0, 0);
        measuredHeight = headView.getMeasuredHeight();
        headView.setPadding(0, -measuredHeight, 0, 0);
        initAnimation();
    }

處理Listview的點擊事件

/**
     * 重新onTouchEvent,處理點擊事件
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                if (downY == -1){
                    downY = (int) ev.getY();
                }
//                downY = (int) ev.getY();
            break;
            case MotionEvent.ACTION_MOVE:
                if (downY == -1){
                    downY = (int) ev.getY();
                }
                int moveY = (int) ev.getY();
                int diffY = moveY - downY;
                // 判斷當前是否正在刷新中
                if(currentState == RELEASEREFRESH) {
                    // 當前正在刷新中, 不執行下拉, 直接跳出
                    break;
                }

                //如果是從上向下滑動,並且是第一個頭布局,才進行下拉操作
                boolean isDisplay = isDisplaySecondHeaderView();
                if (diffY>0&&isDisplay) {
                    int piddingTop = -measuredHeight+diffY;
                    if (piddingTop >= 0 && currentState != RELEASEREFRESH){
                        Log.i(TAG, "進入釋放刷新狀態");
                        currentState = RELEASEREFRESH;
                        refreshState();
                    }else if (piddingTop<0  && currentState != DOWNREFRESH){
                        Log.i(TAG, "進入下拉刷新");
                        currentState = DOWNREFRESH;
                        refreshState();
                    }
                    headView.setPadding(0,piddingTop,0,0);
                    return true;
                }

                break;
            case MotionEvent.ACTION_UP:
                downY = -1;
                if(currentState == DOWNREFRESH) {
                    // 當前是下拉刷新, 把頭布局的隱藏
                    headView.setPadding(0, -measuredHeight, 0, 0);
                } else if(currentState == RELEASEREFRESH) {
                    // 當前是釋放刷新, 進入到正在刷新中的狀態
                    currentState = INREFRESH;
                    refreshState();

                    headView.setPadding(0, 0, 0, 0);

//                     調用用戶的回調事件, 刷新數據
                    if(mOnRefreshListener != null) {
                        mOnRefreshListener.onPullDownRefresh();
                    }
                }


            break;
        }
        return super.onTouchEvent(ev);

 //判斷3種狀態

 private void refreshState() {
        switch (currentState) {
            case DOWNREFRESH: //下拉刷新
                ivRefresh.startAnimation(downAnima);
                tvRefresh.setText("下拉刷新");
                break;
            case RELEASEREFRESH: //釋放刷新
                ivRefresh.startAnimation(upAnima);
                tvRefresh.setText("松開刷新");
                break;
            case INREFRESH: //刷新中
                ivRefresh.clearAnimation();
                ivRefresh.setVisibility(View.INVISIBLE);
                pbBar.setVisibility(View.VISIBLE);
                tvRefresh.setText("正在刷新中..");
                break;
        }
    }

定義回調接口

public interface OnRefreshListener {

        /**
         * 當下拉刷新時觸發此方法
         */
        public void onPullDownRefresh();

        public void onLoadingMore();
    }

上拉加載更多部分


/**
     * 添加角布局
     */
    private void initFooterView() {
        footView = View.inflate(getContext(), R.layout.listview_footerview, null);
        footView.measure(0,0);
        footViewHeight = footView.getMeasuredHeight();
        this.addFooterView(footView);
        footView.setPadding(0, -footViewHeight, 0, 0);
        this.setOnScrollListener(new OnScrollListener() {
            //當頁面改變是調用
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                // 當滾動停止時, 或者慣性滑動時, ListView最後一個顯示的條目索引為getCount -1;
                if(scrollState == SCROLL_STATE_IDLE ||
                        scrollState == SCROLL_STATE_FLING) {
                    if(getLastVisiblePosition() == getCount() -1 && !isLoadingMore) {
                        System.out.println("滾動到底部了");

                        isLoadingMore  = true;

                        footView.setPadding(0, 0, 0, 0);
                        // 讓ListView滾動到底部
                        setSelection(getCount());

                        // 調用使用者的回調事件
                        if(mOnRefreshListener != null) {
                            mOnRefreshListener.onLoadingMore();
                        }
                    }
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

            }
        });
    }

NewsDetailUI類(Listview頁面item條目的事件處理)

image

點擊listview條目進入一個新的頁面,通過WebView展示一個web網頁

listNews.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                int newsposition = position - 2;
                newsBeanItem = newsItem.get(newsposition);
                // 先把已讀新聞的id取出來
                String readableIDArray = CacheUtils.getString(mActivity, READABLE_NEWS_ID_ARRAY_KEY, "");
                if(!readableIDArray.contains(newsBeanItem.getId()+"")) {
                    String currentID = null;
                    if(TextUtils.isEmpty(readableIDArray)) {
                        currentID = newsBeanItem.getId() + ", ";
                    } else {
                        currentID = readableIDArray + newsBeanItem.getId() + ", ";
                    }
                    // 把這條新聞的id存儲起來
                    CacheUtils.putString(mActivity, READABLE_NEWS_ID_ARRAY_KEY, currentID);
                }

                listNewsAdapter.notifyDataSetChanged();

                Intent intent = new Intent(mActivity, NewsDetailUI.class);
                intent.putExtra("url", newsBeanItem.getUrl());
                intent.putExtra("title",newsBeanItem.getTitle());
                mActivity.startActivity(intent);
            }
        });

初始化數據

private void initData() {
        mIbFinish.setVisibility(View.VISIBLE);
        mIbTextSize.setVisibility(View.VISIBLE);
        mIbShare.setVisibility(View.VISIBLE);
        mTvTitle.setMaxWidth(600);
        mTvTitle.setMaxLines(1);
        mTvTitle.setEllipsize(TextUtils.TruncateAt.valueOf("END"));
        mTvTitle.setText(getIntent().getStringExtra("title"));
        String url = getIntent().getStringExtra("url");
        settings = mWebView.getSettings();
//        settings.setJavaScriptEnabled(true); // 啟用javascript腳本
//        settings.setBuiltInZoomControls(true); // 啟用界面上放大和縮小按鈕
//        settings.setUseWideViewPort(true); // 啟用雙擊放大, 雙擊縮小功能
        mWebView.setWebViewClient(new WebViewClient() {

            @Override
            public void onPageFinished(WebView view, String url) {
                mPbLoading.setVisibility(View.GONE);
            }
        });

        mWebView.loadUrl(url);
    }

設置字體大小

/**
     * 設置webView的字體大小
     */
    private void setTextSize() {
        AlertDialog.Builder ab = new AlertDialog.Builder(this);
        ab.setTitle("選擇字體大小");
        String[] item = new String[]{"超大號字體","大號字體","正常字體","小號字體","超小號字體"};
        ab.setSingleChoiceItems(item, currentSelectTextSize, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                tempCurrent = which;
            }
        });
        ab.setNeutralButton("確定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                currentSelectTextSize = tempCurrent;
                changeTextSize();
            }
        });
        ab.setPositiveButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        ab.show();
    }

share分享(第三方sdk使用在這裡暫時不做介紹,根據官方文檔一步一步就行了)

/**
     * 一鍵社會化分享
     */
    private void mobShare() {
        ShareSDK.initSDK(this);
        OnekeyShare oks = new OnekeyShare();
        //關閉sso授權
        oks.disableSSOWhenAuthorize();

// 分享時Notification的圖標和文字  2.5.9以後的版本不調用此方法
        //oks.setNotification(R.drawable.ic_launcher, getString(R.string.app_name));
        // title標題,印象筆記、郵箱、信息、微信、人人網和QQ空間使用
        oks.setTitle("智慧北京");
        // titleUrl是標題的網絡鏈接,僅在人人網和QQ空間使用
        oks.setTitleUrl("http://sharesdk.cn");
        // text是分享文本,所有平台都需要這個字段
        oks.setText("我是分享文本");
        // imagePath是圖片的本地路徑,Linked-In以外的平台都支持此參數
        //oks.setImagePath("/sdcard/test.jpg");//確保SDcard下面存在此張圖片
        // url僅在微信(包括好友和朋友圈)中使用
        oks.setUrl("http://sharesdk.cn");
        // comment是我對這條分享的評論,僅在人人網和QQ空間使用
        oks.setComment("我是測試評論文本");
        // site是分享此內容的網站名稱,僅在QQ空間使用
        oks.setSite(getString(R.string.app_name));
        // siteUrl是分享此內容的網站地址,僅在QQ空間使用
        oks.setSiteUrl("http://sharesdk.cn");

// 啟動分享GUI
        oks.show(this);
    }

PhotosPager(組圖頁面的實現)

image

簡單幾步,獲取數據,解析數據
初始化數據

@Override
    public void initData() {
        bitmapUtils = new BitmapUtils(mActivity);
        bitmapUtils.configDefaultBitmapConfig(Bitmap.Config.ARGB_4444);

        url = ConstantUtils.PHOTOSURL;

        //先從緩存中讀取數據
        String photosJsonData = CacheUtils.getString(mActivity, url, null);
        if (photosJsonData != null) {
            parserJsonData(photosJsonData);
        }
        //從網絡上請求數據
        getDataFromNet();
    }


private void getDataFromNet() {
        HttpUtils httpUtils = new HttpUtils();
        httpUtils.send(HttpRequest.HttpMethod.GET, url, new RequestCallBack

解析數據

private void parserJsonData(String result) {
        PhotosBean photosBean = parserJson(result);
        //主要取得數據圖片的url+title
        photoNews = photosBean.getData().getNews();

        //設置listview數據
        PhotoAdapter photoAdapter = new PhotoAdapter();
        llPhotos.setAdapter(photoAdapter);
    }

    private PhotosBean parserJson(String result) {
        Gson gson = new Gson();
        PhotosBean photosBean = gson.fromJson(result, PhotosBean.class);
        return photosBean;
    }


    class PhotoAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return photoNews.size();
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder = null;
            if (convertView == null) {
                viewHolder =  new ViewHolder();
                convertView = View.inflate(mActivity, R.layout.photos_list_item, null);
                viewHolder.ivPhotoPhotos = (ImageView) convertView.findViewById(R.id.iv_photo_photos);
                viewHolder.tvTitlePhotos = (TextView) convertView.findViewById(R.id.tv_title_photos);
                convertView.setTag(viewHolder);
            }else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            PhotosBean.DataBean.NewsBean newsBean = photoNews.get(position);
            viewHolder.tvTitlePhotos.setText(newsBean.getTitle());
            //設置默認圖片
            viewHolder.ivPhotoPhotos.setImageResource(R.drawable.default_bg);
            bitmapUtils.display(viewHolder.ivPhotoPhotos,newsBean.getListimage());
            return convertView;
        }

        public class ViewHolder {
//            @Bind(R.id.iv_photo_photos)
            public ImageView ivPhotoPhotos;
//            @Bind(R.id.tv_title_photos)
            public TextView tvTitlePhotos;

        }
    }

切換視圖

 /**
     * 用於切換視圖的方法
     * @param ib
     */
    public void switchView(ImageButton ib) {
        //more沒有切換是listv
        if (isSingleColumns) {
            llPhotos.setVisibility(View.VISIBLE);
            gvPhoto.setVisibility(View.GONE);
            llPhotos.setAdapter(new PhotoAdapter());
            isSingleColumns =false;
            ib.setImageResource(R.mipmap.icon_pic_list_type);
        }else {
            llPhotos.setVisibility(View.GONE);
            gvPhoto.setVisibility(View.VISIBLE);
            gvPhoto.setAdapter(new PhotoAdapter());
            isSingleColumns =true;
            ib.setImageResource(R.mipmap.icon_pic_grid_type);
        }
    }

至此,本小項目完成。其他頁面暫不做實現,其處理邏輯參考“新聞中心”頁面即可。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved