編輯:關於Android編程
提示:因為該新聞app已經基本完成,所以下方代碼量較大,請謹慎!或者從 ViewPager和Fragment結合使用實現新聞類app(一)一步步向下看!
怎麼樣,效果還可以吧!下面就直接上代碼了:
下面是顯示界面的主Activity:
public class BaseActivity extends FragmentActivity { protected ViewPager viewPager; protected MyLinearLayout mly; protected MyOnPageChangedListener onPageChangedListener; //自定義ViewPager的標題; protected ArrayListlist = 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 Mapa=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 ArrayListlist; 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; } }
public class ImageLoader { private ImageView iv; private String url; private NewsItem item; private LruCachelruCache; 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 ArrayListtop; 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進行完善,如果有什麼意見和建議可以告訴我哦!謝謝!
相信很多人都用過開源項目,特別是android studio普及以後,使用開源庫更方便簡單。而如何上傳開源庫到jcenter供大家方便使用,雖然網上也有教程,但還是遇坑
首先聲明我們通篇用的都是Google開源框架Zxing,要實現的功能有三個 ,生成普通二維碼、生成帶有中心圖片Logo 的二維碼,掃描解析二維碼,直接上效果圖吧首先我們需
一、Ant 打包:(下載ant、配置環境變量就不說了) 1、進入命令行模式,並切換到項目目錄,執行如下命令為ADT創建的項目添加ant build支持: andro
好久沒有寫博客了,最近都在忙。有時候即使是有時間也會很懶,就會想玩一玩,放松放松!一直都沒有什麼時間更新我這個菜鳥的博客了。不過今天不一樣,我要給大家講講怎麼實現許多ap