編輯:關於Android編程
提示:因為該新聞app已經基本完成,所以下方代碼量較大,請謹慎!或者從 ViewPager和Fragment結合使用實現新聞類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;
}
}
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進行完善,如果有什麼意見和建議可以告訴我哦!謝謝!
android開源庫發布到jcenter圖文詳解與填坑
相信很多人都用過開源項目,特別是android studio普及以後,使用開源庫更方便簡單。而如何上傳開源庫到jcenter供大家方便使用,雖然網上也有教程,但還是遇坑
Android中二維碼的生成方法(普通二維碼、中心Logo 二維碼、及掃描解析二維碼)
首先聲明我們通篇用的都是Google開源框架Zxing,要實現的功能有三個 ,生成普通二維碼、生成帶有中心圖片Logo 的二維碼,掃描解析二維碼,直接上效果圖吧首先我們需
Android Ant 和 Gradle 打包流程和效率對比
一、Ant 打包:(下載ant、配置環境變量就不說了) 1、進入命令行模式,並切換到項目目錄,執行如下命令為ADT創建的項目添加ant build支持: andro
Android開發技術學習之下拉刷新功能的實現
好久沒有寫博客了,最近都在忙。有時候即使是有時間也會很懶,就會想玩一玩,放松放松!一直都沒有什麼時間更新我這個菜鳥的博客了。不過今天不一樣,我要給大家講講怎麼實現許多ap