Android学习笔记_48_若水新闻客户端源码剖析

一、新闻客户端布局代码

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);
        }
    }
}
View Code

 

 

posted @ 2014-01-24 11:18  若 ♂ 只如初见  阅读(855)  评论(0编辑  收藏  举报