Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發ViewPager和Fragment結合使用實現新聞類app( 三 )(基本成型的app)

Android開發ViewPager和Fragment結合使用實現新聞類app( 三 )(基本成型的app)

編輯:關於Android編程

提示:因為該新聞app已經基本完成,所以下方代碼量較大,請謹慎!或者從 ViewPager和Fragment結合使用實現新聞類app(一)一步步向下看!

經過幾天的努力,不斷地對之前的代碼進行完善,終於基本完成了該新聞類app的雛形!下面和大家分享一下該成果了。先看看顯示效果:

怎麼樣,效果還可以吧!下面就直接上代碼了:

下面是顯示界面的主Activity:

public class BaseActivity extends FragmentActivity {
    protected ViewPager viewPager;
    protected MyLinearLayout mly;
    protected MyOnPageChangedListener onPageChangedListener;
    
    //自定義ViewPager的標題;
    protected ArrayList list = new ArrayList();
    protected String[]a =new String[]{"頭條","社會","國內","國際","娛樂","體育","軍事","科技","財經","時尚"};
    protected List fragmentList = new ArrayList();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        init();
    }

    private ListViewUtils listViewUtils;
    private AllNewsData allNewsData;
    private void init() {
        listViewUtils=new ListViewUtils();
        allNewsData=new AllNewsData();
        viewPager= (ViewPager) findViewById(R.id.viewPager);
        //設置ViewPager的緩存的頁數的個數,緩存頁面4個左右不影響加載速度,而且可以節省流量,挺不錯的。
        viewPager.setOffscreenPageLimit(4);
        mly = (MyLinearLayout) findViewById(R.id.myLinearLayout);
        onPageChangedListener=new MyOnPageChangedListener(mly);
        initList();
        getFragmentList();
        getTabTitleList();
        viewPager.setAdapter(adapter);
        viewPager.addOnPageChangeListener(onPageChangedListener);
        setonLinerTitleClickListener(mly);
        setViewPagerScrollSpeed();
    }
    
    //這個方法也是在(三)中新增的,通過反射的方法,來改變setCurrentItem()後,ViewPager的滾動速度
    private void setViewPagerScrollSpeed( ) {
        try {
            Field mScroller = null;
            mScroller = ViewPager.class.getDeclaredField("mScroller");
            mScroller.setAccessible(true);
            MyOnViewPagerScroller scroller = new MyOnViewPagerScroller(viewPager.getContext());
            mScroller.set(viewPager, scroller);
        } catch (NoSuchFieldException e) {
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    private void initList(){
        for(int i=0;i

下面是每個新聞列表的Fragment:

 

public class MyFragment extends Fragment {

    //該Fragment就是顯示新聞列表的Fragment
    private int position;
    private MyFragment(int position) {
        this.position = position;
    }
    public static MyFragment getnewInstance(int position) {
        return new MyFragment(position);
    }

    @TargetApi(Build.VERSION_CODES.M)
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_layout, container, false);
        ListView lv = (ListView) v.findViewById(R.id.lv);
        try {
            //開始從網絡加載數據
            new ListViewAsyncTask(getContext(), position, lv).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //為顯示新聞列表的ListView綁定監聽事件,實現點擊過後,查看新聞。
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView adapterView, View view, int i, long l) {
                Intent intent=new Intent(getContext(), MyNewsActivity.class);
                NewsItem a= (NewsItem) AllNewsData.allNews.get(position).get(i);
                intent.putExtra("url",a.getArticleUrl());
                startActivity(intent);
            }
        });

        return v;
    }
}

 

 

用來顯示標題的自定義View

 

//該類為我們的標題欄的自定義View
public class MyLinearLayout extends LinearLayout {

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

    private void init(Context context, AttributeSet attrs) {
        //自定義屬性:
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyLinearLayout);
        title_visible_count = array.getInteger(R.styleable.MyLinearLayout_linear_my_view_count, 0);
        //獲取屏幕的寬和高
        screenInfo = new GetScreenInfo(context);
        getHeight = screenInfo.getScreenHeight();
        getWidth = screenInfo.getScreenWidth();
        initPaintAndLine();
        array.recycle();
    }

    private GetScreenInfo screenInfo;
    private float layoutWidth, layoutHeight;
    public static int title_visible_count;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      /*  重寫onMeasure()方法是為了能適配不同大小的機型,如果我們不重寫該方法,在4.0英寸的手機上和5.5英
      寸的手機上都使用同一個height,那給用戶的感覺肯定是不舒服的,所以我們能通過該方法實現一點簡單的適配
      功能,當然如果你剛開始學習自定義View,那你可以不用重寫該方法,直接在xml中的height值寫成固定值就可以了。
     */
        Log.d("zt", "onmeasure");
        int getWidthpx, widthMode, getHeightpx, heightMode;
        getWidthpx = MeasureSpec.getSize(widthMeasureSpec);
        widthMode = MeasureSpec.getMode(widthMeasureSpec);
        getHeightpx = MeasureSpec.getSize(heightMeasureSpec);
        heightMode = MeasureSpec.getMode(heightMeasureSpec);

       /* 該出Mode一共有3中,EXACTLY,AT_MOST,UNSPECIFIED;其中當我們在xml中設置了width或者height為match_parent或者某個
        固定值時,那麼這個Mode就是EXACTLY,如果設置成wrap_content的話,那麼這個Mode就是AT_MOST, UNSPECIFIED是什麼我也不太清楚,
        如果你用過這個值,可以告訴留言告訴我啊!哈哈!*/
        if (widthMode == MeasureSpec.EXACTLY) {
            //當xml中width被設置成了固定的值或者設置成match_parent那麼我們就直接用這個值
            layoutWidth = getWidthpx;
        } else {
            //否則我們就使用getScreenSize()方法中獲得的屏幕的寬度。
            layoutWidth = getWidth;
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            layoutHeight = getHeightpx;
        } else {
            //如果xml中沒有定義高度,那麼我們就讓標題欄占屏幕的1/14,這樣大概差不多比較合適,當然,你可以自己改變這個值。
            layoutHeight = getHeight / 15;
        }
        setMeasuredDimension((int) layoutWidth, (int) layoutHeight);
    }


    private float getHeight, getWidth;

    public Map a=new HashMap();
    private int textViewPosition;
    private TextView getTextView(String name) {
        //因為在新聞的標題欄裡,有很多很多標題,可能多達20個,我們不可能在布局文件裡一直添加吧,所以就直接動態生成TextView.
        TextView tv = new TextView(getContext());
        Log.d("zt", "getTextView");
        a.put(tv,textViewPosition++);

        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        //根據自定義屬性中的控制顯示title數量的值,來動態改變width的值,使得顯示的數量和定義的相符合。
        lp.width = (int) (getWidth / title_visible_count);
        lp.gravity = Gravity.CENTER;
        tv.setText(name + "");
        tv.setGravity(Gravity.CENTER);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15);
        tv.setTextColor(Color.GRAY);
        tv.setLayoutParams(lp);
        return tv;
    }

    private int count;

    //該自定義View中暴露出來的方法,讓外界調用
    public void createTextView(ArrayList list) {
        if (list != null && list.size() > 0) {
            this.removeAllViews();
            count = list.size();
            for (int i = 0; i < list.size(); i++) {
                MyLinearLayout.this.addView(getTextView(list.get(i) + ""));
            }
        }
    }

    //10.2
    private Paint paint;
    private float mLineWidth;
    private float lineEndX;
    private float lineStartX;
    private int currentPositon;
    private void initPaintAndLine() {
        paint = new Paint();
        paint.setStrokeWidth(4);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        //  mLineWidth=  (getWidth/title_visible_count*2/3);
        mLineWidth = getWidth / (title_visible_count * 2);
        lineEndX = (int) (mLineWidth + mLineWidth);
        lineStartX = (getWidth / title_visible_count - mLineWidth) / 2.0f;
    }

    private MyLinearChangedListener myLinearChangeListener;

    public void setOnMyLiChangListener(MyLinearChangedListener my) {
        myLinearChangeListener = my;
    }

    //回調接口
    public interface MyLinearChangedListener {
        void onMyLiChed();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawLine(lineStartX, getMeasuredHeight(), lineEndX, getMeasuredHeight(), paint);
        Log.d("zt", "onDraw");
    }

    private float titleWidth;
    //暴露該方法讓外界調用,來動態改變標題底部的紅色的線,以及標題的顏色
    public void lineScroll(int position, float offset) {

        titleWidth = getWidth / title_visible_count;
        if ((offset * getWidth) < (getWidth / 2)) {
            lineEndX = mLineWidth + titleWidth * offset * 2.0f + titleWidth * position + titleWidth * 1.0f / 4.0f;
        } else {
            lineStartX = lineEndX - (1.0f - offset) * 2.0f * titleWidth - mLineWidth;
        }
        Log.d("hehe", lineEndX - lineStartX + "");
        invalidate();
        linearScroll(position, offset);
    }

    private void linearScroll(int position,float offset){
        currentPositon=position;
        float titleWidth=getWidth/title_visible_count;
        if(position>=(title_visible_count/2)&&offset>0&&getChildCount()>title_visible_count&&position<=5){
                this.scrollTo((int) ((position-(title_visible_count-4))*titleWidth+(titleWidth*offset)),0);
        }
    }

    public void setTitleBackGround(int position) {
      for(int i=0;i



 

下面是ListView的適配器
public class MyListViewBaseAdapter extends BaseAdapter implements AbsListView.OnScrollListener {
    private ArrayList list;
    private int position;
    private Context context;
    private int dataCount;
    private ViewHolder holder;
    private ListView lv;

    //定義LruCache
    private LruCache lruCache;

    public MyListViewBaseAdapter(ArrayList ll, Context context, int datacount, int position, ListView listView) {
        this.list = ll;
        this.context = context;
        this.position = position;
        this.lv = listView;
        //獲取最大緩存值
        int memorisize = (int) Runtime.getRuntime().maxMemory();
        //初始化LruCache並未該LruCache分配最大的緩存值
        lruCache = new LruCache(memorisize / 4) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                //返回存儲進緩存的Bitmap的大小
                return value.getByteCount();
            }
        };
        dataCount = datacount;
    }

    @Override
    public int getCount() {
        return dataCount;
    }

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

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

    private ImageView imageView;
    private TextView author, date, title;

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        holder = new ViewHolder();
        if (view == null) {
            view = LayoutInflater.from(context).inflate(R.layout.list_item_view, null);
            holder.iv = (ImageView) view.findViewById(R.id.imageView);
            holder.title = (TextView) view.findViewById(R.id.text_title);
            holder.author = (TextView) view.findViewById(R.id.author);
            holder.date = (TextView) view.findViewById(R.id.date);
            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }
        holder.iv.setTag(list.get(i).getImageUrl());
        holder.iv.setImageBitmap(null);
        //因為加載圖片需要耗較長時間,不能將文字和圖片在同一個AsyncTask中加載,否則很影響觀感,所以重新開啟一個AsyncTask來加載圖片
        new ImageLoader(holder.iv, list.get(i).getImageUrl(), list.get(i), lruCache).imageLoaderAsynctask();
        holder.title.setText(list.get(i).getTitle());
        holder.date.setText(list.get(i).getDate());
        holder.author.setText(list.get(i).getAuthor());
        return view;
    }

    class ViewHolder {
        ImageView iv;
        TextView author, date, title;
    }

    private int startItem, endItem;
    private ArrayList newsItems;
    private List urlList;

    //獲取在ListViewAsyncTask中已經獲取的網絡數據,並已經封裝過的顯示圖片的URL、
    private void getImageUrl(int startItem, int endItem) {
        newsItems = (ArrayList) AllNewsData.allNews.get(position).subList(startItem, endItem);
        urlList = new ArrayList();
        for (int ii = 0; ii < newsItems.size(); ii++) {
            newsItems.get(ii).getImageUrl();
        }

    }


    @Override
    public void onScrollStateChanged(AbsListView absListView, int i) {
        getImageUrl(startItem, endItem);
        if (i == SCROLL_STATE_IDLE) {
            for (int ii = 0; ii < urlList.size(); ii++) {
                new ImageLoader((ImageView) lv.findViewWithTag(urlList.get(ii)), urlList.get(ii), newsItems.get(ii), lruCache).imageLoaderAsynctask();
            }

        }
    }

    @Override
    public void onScroll(AbsListView absListView, int i, int i1, int i2) {

        startItem = i;
        endItem = i2;

    }

}

 


下面是專門加載圖片的AsyncTask:

public class ImageLoader {

    private ImageView iv;
    private String url;
    private NewsItem item;
    private LruCache lruCache;

    public ImageLoader(ImageView iv, String url, NewsItem item, LruCache lruCache) {
        this.iv = iv;
        this.url = url;
        this.item = item;
        //傳進來LruCache
        this.lruCache = lruCache;
    }

    //通過url來從緩存中獲取對應的Bitmap
    private Bitmap getBitmapFromLruCache(String url) {
        return lruCache.get(url);
    }

    //將Bitmap設置進緩存中
    private void setBitmapInLruCache(String url, Bitmap bitmap) {
        Bitmap bitmap1 = getBitmapFromLruCache(url);
        if (bitmap1 == null) {
            lruCache.put(url, bitmap);
        }
    }

    public void imageLoaderAsynctask() {
        //加載圖片之前先判斷緩存中是否有該圖片,如果存在,那麼就直接使用緩存中的圖片,否則通過網絡數據加載。
        Bitmap bitmap = getBitmapFromLruCache(url);
        if (bitmap != null) {
            if (iv.getTag().equals(url)) {
                iv.setImageBitmap(bitmap);
            }
        } else
            //緩存中不存在該數據,通過網絡加載該數據。
            new ImageLoaderAsynctask().execute();
    }

    private Bitmap bitmap = null;

    class ImageLoaderAsynctask extends AsyncTask {
        @Override
        protected Object doInBackground(Object[] objects) {

            try {
                bitmap = ParseData.getImageView(new URL(url));
                if (bitmap != null) {
                    item.setImageView(bitmap);

                    Log.d("ztt", url + "..." + bitmap);
                }
                //判斷緩存中是否存在該數據
                if (getBitmapFromLruCache(url) == null) {
                    //將通過網絡加載的圖片放入緩存中。
                    setBitmapInLruCache(url, bitmap);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            return bitmap;
        }

        @Override
        protected void onPostExecute(Object o) {
            //通過URL判斷該Bitmap是否匹配當前的IamgeView,如果匹配,就顯示,否則不顯示,這樣能避免圖片顯示錯亂
            if (iv.getTag().equals(url)) {
                iv.setImageBitmap((Bitmap) o);
            } else {

            }
        }
    }
}

 

 

下面是加載ListView數據的AsyncTask
public class ListViewAsyncTask extends AsyncTask {
//為ListView中新聞列表加載數據的AsyncTask類
    private String url;
    private Context context;
    private int position;
    private ProgressDialog dialog;
    private ListViewGetData getListViewData;
    private MyListViewBaseAdapter adapter;
    private ListView lv;

    public ListViewAsyncTask(Context context, int position, ListView lv) throws IOException {
        this.url = url;
        this.context = context;
        this.position = position;
        getListViewData = new ListViewGetData(position);
        this.lv = lv;
    }
    
    @Override
    protected Object doInBackground(Object[] objects) {
        try {
            Log.d("zt", "doInBackGround");
            Log.d("zt",getListViewData+"");
            //在此處加載網絡數據,並將數據進行封裝。
            getListViewData.startGetData();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        //為ListView的Adapter綁定數據,也就是使用上面獲取的已經封裝的數據
        adapter = new MyListViewBaseAdapter(AllNewsData.allNews.get(position), context, AllNewsData.allNews.get(position).size(), position, lv);
        return adapter;
    }

    @Override
    protected void onPostExecute(Object o) {
        lv.setAdapter((ListAdapter) o);
    }
}

 


 

下面是專門用來解析並對數據進行封裝的類:

public class ParseData {

    private String da;
    private ArrayList allNewsItem;
    private int position;
    public ParseData(String s, int position){
        da=s;
        this.position=position;
        Log.d(ListViewUtils.TAG,"parseData");
        allNewsItem=AllNewsData.allNews.get(position);
    }
            //將網絡數據進行解析並進行封裝
    public void getJsonData() throws JSONException, IOException {
        Log.d(ListViewUtils.TAG,"getJsonData");
        JSONObject datas=new JSONObject(da);
        JSONObject result=datas.getJSONObject("result");
        JSONArray data=result.getJSONArray("data");
        Log.d(ListViewUtils.TAG, data.length() + "dataLength");
        //數據進行封裝
        for(int i=0;i

 

下面是用來保存數據的類:

 

public class AllNewsData {

    public static ArrayList top;
    public static ArrayList shehui;
    public static ArrayList guonei;
    public static ArrayList guoji;
    public static ArrayList yule;
    public static ArrayList tiyu;
    public static ArrayList junshi;
    public static ArrayList keji;
    public static ArrayList shishang;
    public static ArrayList caijing;

    public static ArrayList newsCount;

    private static Map topData;
    private static Map junshiData;
    private static Map guoneiData;
    private static Map guojiData;
    private static Map yuleData;
    private static Map shehuiData;
    private static Map tiyuData;
    private static Map kejiData;
    private static Map shishangData;
    private static Map caijingData;

    public static ArrayList allNews;

    public AllNewsData(){
        //用來封裝不同標題的新聞的集合
        newsCount=new ArrayList();
        top=new ArrayList();
        shehui=new ArrayList();
        guoji=new ArrayList();
        guonei=new ArrayList();
        yule=new ArrayList();
        tiyu=new ArrayList();
        junshi=new ArrayList();
        keji=new ArrayList();
        shishang=new ArrayList();
        caijing=new ArrayList();

 /*       topData= new HashMap();
        junshiData=new HashMap();
        guoneiData=new HashMap();
        guojiData=new HashMap();
        yuleData=new HashMap();
        shehuiData=new HashMap();
        tiyuData=new HashMap();
        kejiData=new HashMap();
        shishangData=new HashMap();
        caijingData=new HashMap();*/
        
        //將含有不同title的新聞的集合,繼續進行封裝
        allNews=new ArrayList();
        allNews.add(top);
        allNews.add(shehui);
        allNews.add(guonei);
        allNews.add(guoji);
        allNews.add(yule);
        allNews.add(tiyu);
        allNews.add(junshi);
        allNews.add(keji);
        allNews.add(caijing);
        allNews.add(shishang);

    }
}

 


好了,基本的重要的類就在上面了,還有很多小的輔助的類就不一一貼上來了,因為代碼裡主要的地方都做了注釋,所以就不一一解釋了,如果有什麼不明白的地方,可以留言進行討論哦。

 

因為這只是初步的新聞的app,後面我會繼續完善該後面我會繼續對該app進行完善,如果有什麼意見和建議可以告訴我哦!謝謝!

 

 

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