一、新闻客户端布局代码

1.1 主界面布局

    使用GridView实现左右可滑动菜单项,使用标签HorizontalScrollView实现水平滚动条,将创建的GridView添加到布局文件中。 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@id/main_layout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/main_background"
>
<RelativeLayout
android:id="@id/titlebar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/titlebar_background"
>
<TextView
android:id="@id/titlebar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8.0dip"
android:layout_marginLeft="15.0dip"
android:textAppearance="@style/titlebar_title_style"
android:text="@string/app_name"/>
<Button
android:id="@id/titlebar_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/titlebar_btn_refresh_selector"
android:layout_marginTop="7.0dip"
android:layout_marginRight="14.0dip"
android:layout_alignParentRight="true"
/>
<ProgressBar
android:id="@id/loadnews_progress"
android:layout_width="25.0dip"
android:layout_height="25.0dip"
android:clickable="false"
android:visibility="gone"
android:layout_marginRight="20.0dip"
android:layout_marginTop="10.0dip"
android:layout_alignParentRight="true"
style="?android:attr/progressBarStyleLarge" />
</RelativeLayout>
<RelativeLayout
android:id="@id/categorybar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/categorybar_background"
android:layout_marginTop="-18.0dip"
>
<Button
android:id="@id/category_arrow_right"
android:layout_width="6.0dip"
android:layout_height="10.0dip"
android:background="@drawable/categorybar_right_arrow"
android:layout_marginLeft="2.0dip"
android:layout_marginRight="10.0dip"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
<HorizontalScrollView
android:id="@id/category_scrollview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6.0dip"
android:scrollbars="none"
android:layout_toLeftOf="@id/category_arrow_right"
android:layout_centerVertical="true">
<LinearLayout
android:id="@id/category_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
/>
</HorizontalScrollView>
</RelativeLayout>
<ListView
android:id="@+id/newslist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:listSelector="@drawable/newslist_item_selector"
android:cacheColorHint="#00000000"
android:divider="@drawable/list_separator_line"
/>
</LinearLayout>

二、ViewFlipper的应用

2.1 界面布局

    进入到新闻详细界面,通过手指滑动实现下一条新闻和上一条新闻的切换。newsdetails.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@id/newsdetails_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/main_background"
android:layout_marginBottom="0.0dip"
>
<RelativeLayout
android:id="@id/newsdetails_titlebar_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/titlebar_background"
>
<Button
android:id="@id/newsdetails_titlebar_previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="7.0dip"
android:layout_marginLeft="5.0dip"
android:layout_alignParentLeft="true"
android:background="@drawable/newsdetails_title_previous_btn_selector"
android:textSize="14.0sp"
android:textStyle="bold"
/>
<TextView
android:id="@id/newsdetails_titlebar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15.0dip"
android:layout_marginTop="10.0dip"
android:layout_toRightOf="@id/newsdetails_titlebar_previous"
android:textSize="18.0sp"
android:textColor="@color/white"
android:text="国内"
/>
<Button
android:id="@id/newsdetails_titlebar_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="7.0dip"
android:layout_marginRight="5.0dip"
android:layout_alignParentRight="true"
android:background="@drawable/newsdetails_title_next_btn_selector"
/>
<Button
android:id="@id/newsdetails_titlebar_comments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="60.0dip"
android:layout_marginTop="9.0dip"
android:background="@drawable/newsdetails_titlebar_comments_background"
android:textColor="@color/white"
android:text="0跟帖"
/>
<ProgressBar
android:id="@id/loadnews_progress"
android:layout_width="25.0dip"
android:layout_height="25.0dip"
android:clickable="false"
android:visibility="gone"
android:layout_marginRight="30.0dip"
android:layout_marginTop="10.0dip"
android:layout_alignParentRight="true"
style="?android:attr/progressBarStyleLarge" />
</RelativeLayout> <ViewFlipper
android:id="@id/news_body_flipper"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/main_background"
android:layout_marginTop="-12.0dip"
android:layout_marginBottom="40.0dip"
android:layout_below="@id/newsdetails_titlebar_layout" /> <include
android:id="@id/comments_reply_frame"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
layout="@layout/reply_frame" />
</RelativeLayout>

news_body.xml

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:szy="http://schemas.android.com/apk/res/com.szy.news.activity"
android:id="@id/news_body_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@id/newsdetails_titlebar_layout"
>
<ScrollView
android:id="@id/news_body_scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFE7E7E7"
android:fadingEdge="none"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@id/news_body_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12.0dip"
android:layout_marginTop="12.0dip"
android:layout_marginRight="12.0dip"
android:textColor="#FF272727"
android:textSize="18.0dip"
android:textStyle="bold"
/>
<TextView
android:id="@id/news_body_ptime_source"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12.0dip"
android:layout_marginTop="9.0dip"
android:layout_marginRight="12.0dip"
android:textColor="#FF888888"
android:textSize="12.0sp"
/>
<ImageView
android:id="@id/news_body_separator_line"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8.0dip"
android:visibility="visible"
android:src="@drawable/list_separator_line"
/>
<ProgressBar
android:id="@id/news_body_details_loading"
android:layout_width="16.0dip"
android:layout_height="16.0dip"
android:layout_marginLeft="152.0dip"
android:layout_marginTop="10.0dip"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:visibility="gone"
android:clickable="false"
style="?android:attr/progressBarStyleLarge" />
</LinearLayout>
<!--
<TextView
android:id="@id/news_body_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5.0dip"
android:textColor="#ff000000"
/>
-->
<com.szy.news.view.CustomTextView
android:id="@id/news_body_details"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
szy:image_width="200dip"
szy:image_height="52dip"
/>
</LinearLayout>
</ScrollView>
</LinearLayout>

详细新闻的activity的实现,通过自定义控件显示新闻内容,监听新闻内容的触摸事件:

package com.szy.news.activity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import org.json.JSONArray;
import org.json.JSONObject; import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper; import com.szy.news.model.Parameter;
import com.szy.news.service.SyncHttp;
import com.szy.news.view.CustomTextView; /**
*@author coolszy
*@date 2012-3-19
*@blog http://blog.92coding.com
*/
public class NewsDetailsActivity extends Activity
{
private final int FINISH = 0; private ViewFlipper mNewsBodyFlipper;
private LayoutInflater mNewsBodyInflater;
private float mStartX;
private ArrayList<HashMap<String, Object>> mNewsData;
private int mPosition = 0;
private int mCursor;
private int mNid;
private CustomTextView mNewsDetails;
private Button mNewsdetailsTitlebarComm;// 新闻回复数
private ImageButton mNewsReplyImgBtn;// 发表新闻回复图片
private LinearLayout mNewsReplyImgLayout;// 发表新闻回复图片Layout
private LinearLayout mNewsReplyEditLayout;// 发表新闻回复回复Layout
private TextView mNewsReplyContent;// 新闻回复内容
private boolean keyboardShow = false; //软件盘是否可见 private Handler mHandler = new Handler()
{
@SuppressWarnings("unchecked")
@Override
public void handleMessage(Message msg)
{
switch (msg.arg1)
{
case FINISH:
// 把获取到的新闻显示到界面上
ArrayList<HashMap<String, Object>> bodyList = (ArrayList<HashMap<String,Object>>)msg.obj;
System.out.println("###:"+bodyList.size());
mNewsDetails.setText(bodyList);
break;
}
}
}; @SuppressWarnings("unchecked")
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.newsdetails); // 查找新闻回复图片Layout
mNewsReplyImgLayout = (LinearLayout) findViewById(R.id.news_reply_img_layout);
// 查找新闻回复回复Layout
mNewsReplyEditLayout = (LinearLayout) findViewById(R.id.news_reply_edit_layout);
// 新闻回复内容
mNewsReplyContent = (TextView) findViewById(R.id.news_reply_edittext); NewsDetailsOnClickListener newsDetailsOnClickListener = new NewsDetailsOnClickListener();
// 上一篇新闻
Button newsDetailsTitlebarPref = (Button) findViewById(R.id.newsdetails_titlebar_previous);
newsDetailsTitlebarPref.setOnClickListener(newsDetailsOnClickListener);
// 下一篇新闻
Button newsDetailsTitlebarNext = (Button) findViewById(R.id.newsdetails_titlebar_next);
newsDetailsTitlebarNext.setOnClickListener(newsDetailsOnClickListener);
// 新闻回复条数Button
mNewsdetailsTitlebarComm = (Button) findViewById(R.id.newsdetails_titlebar_comments);
mNewsdetailsTitlebarComm.setOnClickListener(newsDetailsOnClickListener);
// 发表新闻回复图片Button
mNewsReplyImgBtn = (ImageButton) findViewById(R.id.news_reply_img_btn);
mNewsReplyImgBtn.setOnClickListener(newsDetailsOnClickListener);
// 发表回复
Button newsReplyPost = (Button) findViewById(R.id.news_reply_post);
newsReplyPost.setOnClickListener(newsDetailsOnClickListener); // 获取传递的数据
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
// 设置标题栏名称
String categoryName = bundle.getString("categoryName");
TextView titleBarTitle = (TextView) findViewById(R.id.newsdetails_titlebar_title);
titleBarTitle.setText(categoryName);
// 获取新闻集合
Serializable s = bundle.getSerializable("newsDate");
mNewsData = (ArrayList<HashMap<String, Object>>) s;
// 获取点击位置
mCursor = mPosition = bundle.getInt("position"); // 动态创建新闻视图,并赋值
mNewsBodyInflater = getLayoutInflater();
inflateView(0);
} /**
* 处理NewsDetailsTitleBar点击事件
*/
class NewsDetailsOnClickListener implements OnClickListener
{
@Override
public void onClick(View v)
{
InputMethodManager m = (InputMethodManager) mNewsReplyContent.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
switch (v.getId())
{
// 上一条新闻
case R.id.newsdetails_titlebar_previous:
showPrevious();
break;
// 下一条新闻
case R.id.newsdetails_titlebar_next:
showNext();
break;
// 显示评论
case R.id.newsdetails_titlebar_comments:
Intent intent = new Intent(NewsDetailsActivity.this, CommentsActivity.class);
//传递新闻ID
intent.putExtra("nid", mNid);
startActivity(intent);
break;
// 新闻回复图片
case R.id.news_reply_img_btn:
mNewsReplyImgLayout.setVisibility(View.GONE);
mNewsReplyEditLayout.setVisibility(View.VISIBLE);
mNewsReplyContent.requestFocus();
m.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT);
keyboardShow = true;
break;
// 发表新闻回复
case R.id.news_reply_post:
mNewsReplyEditLayout.post(new PostCommentThread());
mNewsReplyImgLayout.setVisibility(View.VISIBLE);
mNewsReplyEditLayout.setVisibility(View.GONE);
m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
break;
}
}
} /**
* 处理新闻NewsBody触摸事件
*/
class NewsBodyOnTouchListener implements OnTouchListener
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
switch (event.getAction())
{
// 手指按下
case MotionEvent.ACTION_DOWN:
if (keyboardShow)
{
// 设置新闻回复Layout是否可见
mNewsReplyImgLayout.setVisibility(View.VISIBLE);
mNewsReplyEditLayout.setVisibility(View.GONE);
InputMethodManager m = (InputMethodManager) mNewsReplyContent.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
keyboardShow = false;
}
// 记录起始坐标
mStartX = event.getX();
break;
// 手指抬起
case MotionEvent.ACTION_UP:
// 往左滑动
if (event.getX() < mStartX)
{
showPrevious();
}
// 往右滑动
else if (event.getX() > mStartX)
{
showNext();
}
break;
}
return true;
}
} /**
* 显示下一条新闻
*/
private void showNext()
{
// 判断是否是最后一篇win问:mPosition: 当前新闻的索引
if (mPosition < mNewsData.size() - 1)
{
// 设置下一屏动画
mNewsBodyFlipper.setInAnimation(this, R.anim.push_left_in);
mNewsBodyFlipper.setOutAnimation(this, R.anim.push_left_out);
mPosition++;
HashMap<String, Object> hashMap = mNewsData.get(mPosition);
mNid = (Integer) hashMap.get("nid");
// 判断下一屏是否已经创建
if (mPosition >= mNewsBodyFlipper.getChildCount())
{
inflateView(mNewsBodyFlipper.getChildCount());
}
// 显示下一屏
mNewsBodyFlipper.showNext();
} else
{
Toast.makeText(this, R.string.no_next_news, Toast.LENGTH_SHORT).show();
}
System.out.println(mCursor + ";" + mPosition);
} private void showPrevious()
{
if (mPosition > 0)
{
mPosition--;
// 记录当前新闻编号
HashMap<String, Object> hashMap = mNewsData.get(mPosition);
mNid = (Integer) hashMap.get("nid");
if (mCursor > mPosition)
{
mCursor = mPosition;
inflateView(0);
System.out.println(mNewsBodyFlipper.getChildCount());
mNewsBodyFlipper.showNext();// 显示下一页
}
mNewsBodyFlipper.setInAnimation(this, R.anim.push_right_in);// 定义下一页进来时的动画
mNewsBodyFlipper.setOutAnimation(this, R.anim.push_right_out);// 定义当前页出去的动画
mNewsBodyFlipper.showPrevious();// 显示上一页
} else
{
Toast.makeText(this, R.string.no_pre_news, Toast.LENGTH_SHORT).show();
}
} private void inflateView(int index)
{
// 动态创建新闻视图,并赋值
View newsBodyLayout = mNewsBodyInflater.inflate(R.layout.news_body, null);
// 获取点击新闻基本信息
HashMap<String, Object> hashMap = mNewsData.get(mPosition);
// 新闻标题
TextView newsTitle = (TextView) newsBodyLayout.findViewById(R.id.news_body_title);
newsTitle.setText(hashMap.get("newslist_item_title").toString());
// 发布时间和出处
TextView newsPtimeAndSource = (TextView) newsBodyLayout.findViewById(R.id.news_body_ptime_source);
newsPtimeAndSource.setText(hashMap.get("newslist_item_ptime").toString() + " " + hashMap.get("newslist_item_source").toString());
// 新闻编号
mNid = (Integer) hashMap.get("nid");
// 新闻回复数
mNewsdetailsTitlebarComm.setText(hashMap.get("newslist_item_comments") + "跟帖"); // 把新闻视图添加到Flipper中
mNewsBodyFlipper = (ViewFlipper) findViewById(R.id.news_body_flipper);
mNewsBodyFlipper.addView(newsBodyLayout, index); // 给新闻Body添加触摸事件
mNewsDetails = (CustomTextView) newsBodyLayout.findViewById(R.id.news_body_details);
mNewsDetails.setOnTouchListener(new NewsBodyOnTouchListener()); // 启动线程
new UpdateNewsThread().start();
} /**
* 获取新闻详细信息
*
* @return
*/
private ArrayList<HashMap<String, Object>> getNewsBody()
{
// String retStr = "网络连接失败,请稍后再试";
ArrayList<HashMap<String, Object>> bodyList = new ArrayList<HashMap<String,Object>>();
SyncHttp syncHttp = new SyncHttp();
String url = "http://10.0.2.2:8080/web/getNews";
String params = "nid=" + mNid;
try
{
String retString = syncHttp.httpGet(url, params);
JSONObject jsonObject = new JSONObject(retString);
// 获取返回码,0表示成功
int retCode = jsonObject.getInt("ret");
if (0 == retCode)
{
JSONObject dataObject = jsonObject.getJSONObject("data");
JSONObject newsObject = dataObject.getJSONObject("news");
// 测试自定义控件
// retStr = newsObject.getString("body");
JSONArray bodyArray = newsObject.getJSONArray("body");
for (int i=0;i<bodyArray.length();i++)
{
JSONObject object = (JSONObject)bodyArray.opt(i);
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("index", object.get("index"));
hashMap.put("type", object.get("type"));
hashMap.put("value", object.get("value"));
bodyList.add(hashMap);
}
} } catch (Exception e)
{
e.printStackTrace();
}
// 测试自定义控件
// return retStr;
return bodyList;
} /**
* 更新新闻内容
*
* @author coolszy
*@date 2012-4-22
*@blog http://blog.92coding.com
*/
private class UpdateNewsThread extends Thread
{
@Override
public void run()
{
// 从网络上获取新闻
// 测试自定义控件
// String newsBody = getNewsBody();
ArrayList<HashMap<String, Object>> bodyList = getNewsBody();
Message msg = mHandler.obtainMessage();
System.out.println("@@@:"+bodyList.size());
msg.arg1 = FINISH;
msg.obj = bodyList;
mHandler.sendMessage(msg);
}
} /**
* 发表回复
*
* @author coolszy
*@date 2012-4-22
*@blog http://blog.92coding.com
*/
private class PostCommentThread extends Thread
{
@Override
public void run()
{
SyncHttp syncHttp = new SyncHttp();
String url = "http://10.0.2.2:8080/web/postComment";
List<Parameter> params = new ArrayList<Parameter>();
params.add(new Parameter("nid", mNid + ""));
params.add(new Parameter("region", "江苏省连云港市"));
params.add(new Parameter("content", mNewsReplyContent.getText().toString()));
try
{
String retStr = syncHttp.httpPost(url, params);
JSONObject jsonObject = new JSONObject(retStr);
int retCode = jsonObject.getInt("ret");
if (0 == retCode)
{
Toast.makeText(NewsDetailsActivity.this, R.string.post_success, Toast.LENGTH_SHORT).show();
mNewsReplyImgLayout.setVisibility(View.VISIBLE);
mNewsReplyEditLayout.setVisibility(View.GONE);
return;
} } catch (Exception e)
{
e.printStackTrace();
}
Toast.makeText(NewsDetailsActivity.this, R.string.post_failure, Toast.LENGTH_SHORT).show();
}
} }

三、自定义控件实现图文混排

1.1 自定义控件图文混排

package com.szy.news.view;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap; import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.Html;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ImageView.ScaleType; import com.szy.news.activity.R; /**
*@author coolszy
*@date 2012-5-1
*@blog http://blog.92coding.com
*/ public class CustomTextView extends LinearLayout
{
private Context mContext;
private TypedArray mTypedArray; public CustomTextView(Context context)
{
this(context, null);
} public CustomTextView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.mContext = context; setOrientation(LinearLayout.VERTICAL);
mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.customTextView); } public void setText(ArrayList<HashMap<String, Object>> datas)
{
for (HashMap<String, Object> hashMap : datas)
{
//如果是图片
if (hashMap.get("type").equals("image"))
{
int imageWidth = mTypedArray.getDimensionPixelOffset(R.styleable.customTextView_image_width, 100);
int imageheight = mTypedArray.getDimensionPixelOffset(R.styleable.customTextView_image_height, 100);
//创建ImageView并设置属性
ImageView imageView = new ImageView(mContext);
LayoutParams params = new LayoutParams(imageWidth, imageheight);
params.gravity = Gravity.CENTER_HORIZONTAL;//居中
imageView.setLayoutParams(params);
imageView.setImageResource(R.drawable.kuka);//默认图片
imageView.setScaleType(ScaleType.CENTER_INSIDE);
addView(imageView);
//启动线程,异步加载图片
new DownloadPicThread(imageView,hashMap.get("value").toString()).start();
}
//反之则已文本显示
else
{
//创建TextView并设置属性
TextView textView = new TextView(mContext);
textView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
float textSize = mTypedArray.getDimension(R.styleable.customTextView_textSize, 16);
int textColor = mTypedArray.getColor(R.styleable.customTextView_textColor, 0xFF000000);
textView.setTextSize(textSize);
textView.setTextColor(textColor);
textView.setText(Html.fromHtml(hashMap.get("value").toString()));
addView(textView);
}
}
} private Handler mHandler = new Handler()
{
@SuppressWarnings("unchecked")
@Override
public void handleMessage(Message msg)
{
HashMap<String, Object> hashMap = (HashMap<String, Object>)msg.obj;
ImageView imageView = (ImageView)hashMap.get("imageview");
LayoutParams params = new LayoutParams(msg.arg1,msg.arg2);
params.gravity = Gravity.CENTER_HORIZONTAL;//居中
imageView.setLayoutParams(params);
Drawable drawable = (Drawable)hashMap.get("drawable");
imageView.setImageDrawable(drawable);
} }; private class DownloadPicThread extends Thread
{
private ImageView mImageView;
private String mUrl; public DownloadPicThread(ImageView imageView, String url)
{
super();
this.mImageView = imageView;
this.mUrl = url;
} public void run()
{
Drawable drawable = null;
int newImgWidth = 0;
int newImgHeigth = 0;
try
{
drawable = Drawable.createFromStream(new URL(mUrl).openStream(), "image");
newImgWidth = drawable.getIntrinsicWidth() / 3;
newImgHeigth = drawable.getIntrinsicHeight() / 3;
} catch (Exception e)
{
e.printStackTrace();
}
//为了更好的看到效果,让线程休眠2秒
SystemClock.sleep(2000);
//使用Handler更新UI
Message msg = mHandler.obtainMessage();
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("imageview", mImageView);
hashMap.put("drawable", drawable);
msg.obj = hashMap;
msg.arg1 = newImgWidth;
msg.arg2 = newImgHeigth;
mHandler.sendMessage(msg);
}
}
}

四、新闻客户端布局代码

4.1 使GridView控件第一项默认选中

public class CustomSimpleAdapter extends SimpleAdapter
{ public CustomSimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)
{
super(context, data, resource, from, to);
} @Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = super.getView(position, convertView, parent);
//更新第一个TextView的背景
if (position==0)
{
TextView categoryTitle = (TextView)v;
categoryTitle.setBackgroundResource(R.drawable.categorybar_item_background);
categoryTitle.setTextColor(0XFFFFFFFF);
}
return v;
}
}

4.2 gridview每项切换效果,ListView添加footer

package com.szy.news.activity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import org.json.JSONArray;
import org.json.JSONObject; import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.GridView;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener; import com.szy.news.custom.Category;
import com.szy.news.custom.CustomSimpleAdapter;
import com.szy.news.service.SyncHttp;
import com.szy.news.service.UpdateManager;
import com.szy.news.util.DensityUtil;
import com.szy.news.util.StringUtil; public class MainActivity extends Activity
{
private final int COLUMNWIDTHPX = 55;
private final int FLINGVELOCITYPX = 800; // 滚动距离
private final int NEWSCOUNT = 5; //返回新闻数目
private final int SUCCESS = 0;//加载成功
private final int NONEWS = 1;//该栏目下没有新闻
private final int NOMORENEWS = 2;//该栏目下没有更多新闻
private final int LOADERROR = 3;//加载失败 private int mColumnWidthDip;
private int mFlingVelocityDip;
private int mCid;
private String mCatName;
private ArrayList<HashMap<String, Object>> mNewsData;
private ListView mNewsList;
private SimpleAdapter mNewsListAdapter;
private LayoutInflater mInflater;
private Button mTitlebarRefresh;
private ProgressBar mLoadnewsProgress;
private Button mLoadMoreBtn; private LoadNewsAsyncTask loadNewsAsyncTask; @Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main); mInflater = getLayoutInflater();
mNewsData = new ArrayList<HashMap<String,Object>>();
mNewsList = (ListView)findViewById(R.id.newslist);
mTitlebarRefresh = (Button)findViewById(R.id.titlebar_refresh);
mLoadnewsProgress = (ProgressBar)findViewById(R.id.loadnews_progress);
mTitlebarRefresh.setOnClickListener(loadMoreListener); //把px转换成dip
mColumnWidthDip = DensityUtil.px2dip(this, COLUMNWIDTHPX);
mFlingVelocityDip = DensityUtil.px2dip(this, FLINGVELOCITYPX); //获取新闻分类
String[] categoryArray = getResources().getStringArray(R.array.categories);
//把新闻分类保存到List中
final List<HashMap<String, Category>> categories = new ArrayList<HashMap<String, Category>>();
//分割新闻类型字符串
for(int i=0;i<categoryArray.length;i++)
{
String[] temp = categoryArray[i].split("[|]");
if (temp.length==2)
{
int cid = StringUtil.String2Int(temp[0]);
String title = temp[1];
Category type = new Category(cid, title);
HashMap<String, Category> hashMap = new HashMap<String, Category>();
hashMap.put("category_title", type);
categories.add(hashMap);
}
}
//默认选中的新闻分类
mCid = 1;
mCatName ="国内";
//创建Adapter,指明映射字段
CustomSimpleAdapter categoryAdapter = new CustomSimpleAdapter(this, categories, R.layout.category_title, new String[]{"category_title"}, new int[]{R.id.category_title}); GridView category = new GridView(this);
category.setColumnWidth(mColumnWidthDip);//每个单元格宽度
category.setNumColumns(GridView.AUTO_FIT);//单元格数目
category.setGravity(Gravity.CENTER);//设置对其方式
//设置单元格选择是背景色为透明,这样选择时就不现实黄色北京
category.setSelector(new ColorDrawable(Color.TRANSPARENT));
//根据单元格宽度和数目计算总宽度
int width = mColumnWidthDip * categories.size();
LayoutParams params = new LayoutParams(width, LayoutParams.FILL_PARENT);
//更新category宽度和高度,这样category在一行显示
category.setLayoutParams(params);
//设置适配器
category.setAdapter(categoryAdapter);
//把category加入到容器中
LinearLayout categoryList = (LinearLayout) findViewById(R.id.category_layout);
categoryList.addView(category);
//添加单元格点击事件
category.setOnItemClickListener(new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
TextView categoryTitle;
//恢复每个单元格背景色
for (int i = 0; i < parent.getChildCount(); i++)
{
categoryTitle = (TextView) (parent.getChildAt(i));
categoryTitle.setBackgroundDrawable(null);
categoryTitle.setTextColor(0XFFADB2AD);
}
//设置选择单元格的背景色
categoryTitle = (TextView) (parent.getChildAt(position));
categoryTitle.setBackgroundResource(R.drawable.categorybar_item_background);
categoryTitle.setTextColor(0XFFFFFFFF);
//获取选中的新闻分类id
mCid = categories.get(position).get("category_title").getCid();
mCatName = categories.get(position).get("category_title").getTitle();
//获取该栏目下新闻
//getSpeCateNews(mCid,mNewsData,0,true);
//通知ListView进行更新
//mNewsListAdapter.notifyDataSetChanged();
loadNewsAsyncTask = new LoadNewsAsyncTask();
loadNewsAsyncTask.execute(mCid,0,true);
}
}); // 箭头
final HorizontalScrollView categoryScrollview = (HorizontalScrollView) findViewById(R.id.category_scrollview);
Button categoryArrowRight = (Button) findViewById(R.id.category_arrow_right);
//点击箭头向左移动像素
categoryArrowRight.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
categoryScrollview.fling(DensityUtil.px2dip(MainActivity.this, mFlingVelocityDip));
}
});
//获取指定栏目的新闻列表
//getSpeCateNews(mCid,mNewsData,0,true);
mNewsListAdapter = new SimpleAdapter(this, mNewsData, R.layout.newslist_item,
new String[]{"newslist_item_title","newslist_item_digest","newslist_item_source","newslist_item_ptime"},
new int[]{R.id.newslist_item_title,R.id.newslist_item_digest,R.id.newslist_item_source,R.id.newslist_item_ptime});
//添加页脚
View loadMoreLayout = mInflater.inflate(R.layout.loadmore, null);
mNewsList.addFooterView(loadMoreLayout);
mNewsList.setAdapter(mNewsListAdapter);
//点击新闻列表项,弹出新闻详细界面
mNewsList.setOnItemClickListener(new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Intent intent = new Intent(MainActivity.this, NewsDetailsActivity.class);
//把需要的信息放到Intent中
intent.putExtra("newsDate", mNewsData);
intent.putExtra("position", position);
intent.putExtra("categoryName", mCatName);
startActivity(intent);
}
}); mLoadMoreBtn = (Button)findViewById(R.id.loadmore_btn);
mLoadMoreBtn.setOnClickListener(loadMoreListener); loadNewsAsyncTask = new LoadNewsAsyncTask();
loadNewsAsyncTask.execute(mCid,0,true);
} /**
* 增加菜单
*/
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_item, menu);
return true;
} /**
* 处理菜单事件
*/
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getItemId()==R.id.menu_item_update)
{
UpdateManager manager = new UpdateManager(MainActivity.this);
// 检查软件更新
manager.checkUpdate();
}
return true;
} /**
* 获取指定类型的新闻列表
* @param cid 类型ID
* @param newsList 保存新闻信息的集合
* @param startnid 分页
* @param firstTimes 是否第一次加载
*/
private int getSpeCateNews(int cid,List<HashMap<String, Object>> newsList,int startnid,Boolean firstTimes)
{
if (firstTimes)
{
//如果是第一次,则清空集合里数据
newsList.clear();
}
//请求URL和字符串
String url = "http://10.0.2.2:8080/web/getSpecifyCategoryNews";
String params = "startnid="+startnid+"&count="+NEWSCOUNT+"&cid="+cid;
SyncHttp syncHttp = new SyncHttp();
try
{
//以Get方式请求,并获得返回结果
String retStr = syncHttp.httpGet(url, params);
JSONObject jsonObject = new JSONObject(retStr);
//获取返回码,0表示成功
int retCode = jsonObject.getInt("ret");
if (0==retCode)
{
JSONObject dataObject = jsonObject.getJSONObject("data");
//获取返回数目
int totalnum = dataObject.getInt("totalnum");
if (totalnum>0)
{
//获取返回新闻集合
JSONArray newslist = dataObject.getJSONArray("newslist");
for(int i=0;i<newslist.length();i++)
{
JSONObject newsObject = (JSONObject)newslist.opt(i);
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("nid", newsObject.getInt("nid"));
hashMap.put("newslist_item_title", newsObject.getString("title"));
hashMap.put("newslist_item_digest", newsObject.getString("digest"));
hashMap.put("newslist_item_source", newsObject.getString("source"));
hashMap.put("newslist_item_ptime", newsObject.getString("ptime"));
hashMap.put("newslist_item_comments", newsObject.getString("commentcount"));
newsList.add(hashMap);
}
return SUCCESS;
}
else
{
if (firstTimes)
{
return NONEWS;
}
else
{
return NOMORENEWS;
}
}
}
else
{
return LOADERROR;
}
} catch (Exception e)
{
e.printStackTrace();
return LOADERROR;
}
} private OnClickListener loadMoreListener = new OnClickListener()
{
@Override
public void onClick(View v)
{
loadNewsAsyncTask = new LoadNewsAsyncTask();
switch (v.getId())
{
case R.id.loadmore_btn:
//获取该栏目下新闻
//getSpeCateNews(mCid,mNewsData,mNewsData.size(),false);
//通知ListView进行更新
//mNewsListAdapter.notifyDataSetChanged();
loadNewsAsyncTask.execute(mCid,mNewsData.size(),false);
break;
case R.id.titlebar_refresh:
loadNewsAsyncTask.execute(mCid,0,true);
break;
} }
}; private class LoadNewsAsyncTask extends AsyncTask<Object, Integer, Integer>
{ @Override
protected void onPreExecute()
{
//隐藏刷新按钮
mTitlebarRefresh.setVisibility(View.GONE);
//显示进度条
mLoadnewsProgress.setVisibility(View.VISIBLE);
//设置LoadMore Button 显示文本
mLoadMoreBtn.setText(R.string.loadmore_txt);
} @Override
protected Integer doInBackground(Object... params)
{
return getSpeCateNews((Integer)params[0],mNewsData,(Integer)params[1],(Boolean)params[2]);
} @Override
protected void onPostExecute(Integer result)
{
//根据返回值显示相关的Toast
switch (result)
{
case NONEWS:
Toast.makeText(MainActivity.this, R.string.no_news, Toast.LENGTH_LONG).show();
break;
case NOMORENEWS:
Toast.makeText(MainActivity.this, R.string.no_more_news, Toast.LENGTH_LONG).show();
break;
case LOADERROR:
Toast.makeText(MainActivity.this, R.string.load_news_failure, Toast.LENGTH_LONG).show();
break;
}
mNewsListAdapter.notifyDataSetChanged();
//显示刷新按钮
mTitlebarRefresh.setVisibility(View.VISIBLE);
//隐藏进度条
mLoadnewsProgress.setVisibility(View.GONE);
//设置LoadMore Button 显示文本
mLoadMoreBtn.setText(R.string.loadmore_btn);
}
}
}

Android学习笔记_48_若水新闻客户端源码剖析的更多相关文章

  1. android版高仿淘宝客户端源码V2.3

    android版高仿淘宝客户端源码V2.3,这个版本我已经更新到2.3了,源码也上传到源码天堂那里了,大家可以看一下吧,该应用实现了我们常用的购物功能了,也就是在手机上进行网购的流程的,如查看产品(浏 ...

  2. 机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

    机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理.源码解析及测试 关键字:决策树.python.源码解析.测试作者:米仓山下时间:2018-10-2 ...

  3. 高仿it之家新闻客户端源码

    仿it之家新闻客户端界面,数据为本地假数据.仅实现了新闻模块的功能. 源码下载:http://code.662p.com/list/11_1.html 详细说明:http://android.662p ...

  4. [shiro学习笔记]第四节 使用源码生成Shiro的CHM格式的API文档

    版本号为1.2.3的shiro API chm个事故文档生成. 获取shiro源码 编译生成API文档 转换成chm格式 API 获取shiro源码 shiro官网: http://shiro.apa ...

  5. 并发编程学习笔记(七、Thread源码分析)

    目录: 常见属性 构造函数 start() run() 常见属性: /** * 线程名称 */ private volatile String name; /** * 线程优先级 */ private ...

  6. Elasticsearch客户端源码剖析

    注:本文出自博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 注:本文源链接:https://www.cnblogs.com/chloneda/p/es-cli ...

  7. Android 学习笔记之Volley(七)实现Json数据加载和解析...

    学习内容: 1.使用Volley实现异步加载Json数据...   Volley的第二大请求就是通过发送请求异步实现Json数据信息的加载,加载Json数据有两种方式,一种是通过获取Json对象,然后 ...

  8. Android学习笔记之JSON数据解析

    转载:Android学习笔记44:JSON数据解析 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,为Web应用开发提供了一种 ...

  9. MQTT再学习 -- MQTT 客户端源码分析

    MQTT 源码分析,搜索了一下发现网络上讲的很少,多是逍遥子的那几篇. 参看:逍遥子_mosquitto源码分析系列 参看:MQTT libmosquitto源码分析 参看:Mosquitto学习笔记 ...

随机推荐

  1. JS正则表达式一些基本使用、验证、匹配、正则匹配时一个变量

    js验证首位必须是字母 var str = "asfg"; /^[a-zA-Z].*/.test(str);//true是,false否 匹配所有空格 var str=" ...

  2. 【程序员技术练级】学习一门脚本语言 python(三)跟数据库打交道

    接着上一篇,该篇讲述使用python对数据库进行基本的CRUD操作,这边以sqlite3为例子,进行说明.sqlite3 是一个非常轻型的数据库,安装和使用它是非常简单的,这边就不进行讲述了. 在py ...

  3. docker~run起来之后执行多条命令

    最近在搞jenkins pipeline的部署工作,而在对.net core进行部署时不希望安装dotnet sdk,为了移植性更好,打算直接使用aspnetcore的docker镜像,通过docke ...

  4. Web请求过程总结

    Web请求过程总结 1.CND架构图 图片来源:深入分析JavaWeb技术内幕(许令波著) 2.发起HTTP请求 发起一个HTTP请求就是浏览器建立socket通信的过程,HttpClient开源的通 ...

  5. Java Socket通信示例

    Socket分为ServerSocket和Socket两大类: 其中ServerSocket用于服务器端,可以通过accept方法监听请求,监听到请求后返回Socket: Socket用户具体完成数据 ...

  6. 《C#高效编程》读书笔记02-用运行时常量(readonly)而不是编译期常量(const)

    C#有两种类型的常量:编译期常量和运行时常量.两者有截然不同的行为,使用不当的话,会造成性能问题,如果没法确定,则使用慢点,但能保证正确的运行时常量. 运行时常量使用readonly关键字声明,编译期 ...

  7. frp使用总结

    笔者所知并成功实现内网穿透的方法: 花生壳 (需要花8块钱,使用花生壳给的二级域名,这里不做介绍) ngrok (免费,但是每次重启服务二级域名会变,付费的$5每月不会变) frp(开源免费,需要有自 ...

  8. JS数组遍历方法

    常用数组遍历方法: 1.原始for循环 var a = [1,2,3]; for(var i=0;i<a.length;i++){ console.log(a[i]); //结果依次为1,2,3 ...

  9. (0!=0)==true? 记一个匪夷所思的问题

    最近换了份工作,公司的开发框架是基于SSH自己搭建的.这个问题是我在解决一个需求的时候遇到的,其实解决这个疑惑的过程也就是读框架源码的过程,特此记录一下. 问题:ba.getState()!=CbBa ...

  10. 【学习笔记】实用类String的基本应用即常用方法

    一.String类概述 在Java中,字符串被作为String类型的对象来处理. String类位于java.lang包中,默认情况下会自动导入到所有的程序中. 创建String对象的方法如下: St ...