该Demo抛弃了ListView控件的使用,是直接使用ViewGroup或其子类进行多个子控件封装,从而达到修正多个附件同时下载时,列表中每个控件的显示错乱的问题(如有更好的方法,欢迎交流)。
该Demo采用单线程下载模式,因为项目的需求,所以一直没改。大家可以直接将单线程改为多线程同步,因为该Demo中所用到的适配器就是根据多线程同步而设计的。
下面我会给出整个Demo的完整范例,但没有程序源码,大家可以直接Copy,因为这是直接从我项目中的抽出来的,还请见谅!
好了,废话不多说,开始:
1,先看看适配器的每个Item布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" style="@style/width_fullscreen" android:padding="7dp" android:background="@drawable/list_selector_bg"> <TextView android:id="@+id/AffixName" style="@style/width_fullscreen" android:textSize="17sp" android:textStyle="bold" android:maxLines="2" android:drawablePadding="3.4dp" android:layout_toLeftOf="@+id/AffixDownload" /> <TextView android:id="@+id/AffixNotfoundFileErrormsg" style="@style/width_fullscreen" android:text="@string/download_notfoundfile_errormsg" android:textSize="12sp" android:textColor="@color/red" android:layout_marginTop="5dp" android:layout_marginLeft="20dp" android:layout_marginRight="25dp" android:drawableLeft="@drawable/message_status_fail" android:layout_below="@+id/AffixName" android:background="@drawable/popup" android:visibility="gone" /> <Button android:id="@+id/AffixDownload" style="@style/width_height_free" android:text="@string/download" android:textColor="@color/DarkSlateGray" android:paddingLeft="10.5dp" android:paddingRight="10.5dp" android:drawableRight="@drawable/icon_download_ics" android:drawablePadding="3dp" android:layout_alignParentRight="true" android:layout_alignTop="@+id/AffixName" android:background="@drawable/button_call_bg" /> <RelativeLayout android:id="@+id/AffixDownloadProgressPanel" style="@style/width_fullscreen" android:layout_below="@+id/AffixDownload" android:layout_marginTop="6.5dp" android:visibility="gone"> <ProgressBar android:id="@+id/AffixDownloadProgressbar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="13dp" android:progressDrawable="@drawable/progressbar_background" /> <TextView android:id="@+id/AffixDownloadProgressValue" style="@style/width_height_free" android:textSize="11sp" android:textColor="@color/ghostwhite" android:layout_centerHorizontal="true" /> </RelativeLayout> </RelativeLayout>
2,对应的适配器类:
import java.io.File; import java.util.List; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import com.hwttnet.oa.mobile.aas.R; import com.hwttnet.oa.mobile.app.App; import com.hwttnet.oa.mobile.app.App.Shared; import com.hwttnet.oa.mobile.listener.OnThreadListener; import com.hwttnet.oa.mobile.service.ThreadService; import com.hwttnet.oa.mobile.util.LocationDataProcess; import com.hwttnet.oa.mobile.util.ViewUtil; import com.hwttnet.other.model.AffixInfoBean; /** * 提供多附件下载时的列表适配器 * <HR> * 作者:孙博 * <P> * 时间:2012-11-26 下午4:08:33 * <P> * 电子邮件:[email protected] * <P> * QQ:497733379 * <P> * Gmail : [email protected] */ public class AffixDownloadAdapter implements OnClickListener, OnThreadListener { private final Context context; private final SharedPreferences affixShared; private final ThreadService threadService = new ThreadService(); private final LocationDataProcess locationDateProcess; private final ViewUtil mViewUtil; public AffixDownloadAdapter(Context context) { this.context = context; affixShared = context.getSharedPreferences(Shared.DOWNLOADAFFIXINFO, Context.MODE_PRIVATE); threadService.setOnThreadListener(this); locationDateProcess = new LocationDataProcess(context); mViewUtil = new ViewUtil(context); } public void setupViews(ViewGroup mViewGroup, List<AffixInfoBean> affixs) { if(null == mViewGroup) return; if(mViewGroup.getChildCount() > 0) mViewGroup.removeAllViews(); LayoutInflater layoutInflater = LayoutInflater.from(context); for(AffixInfoBean affix : affixs) { ViewHolder mViewHolder = new ViewHolder(); mViewHolder.affix = affix; mViewHolder.isOpen = false; View convertView = layoutInflater.inflate(R.layout.affix_download_item, null); mViewHolder.mAffixName = (TextView) convertView.findViewById(R.id.AffixName); mViewHolder.mNotfoundFileErrormsg = (TextView) convertView.findViewById(R.id.AffixNotfoundFileErrormsg); mViewHolder.mButton = (Button) convertView.findViewById(R.id.AffixDownload); mViewHolder.mDownloadProgressPanel = (RelativeLayout) convertView.findViewById(R.id.AffixDownloadProgressPanel); mViewHolder.mProgressBar = (ProgressBar) convertView.findViewById(R.id.AffixDownloadProgressbar); mViewHolder.mDownloadProgressValue = (TextView) convertView.findViewById(R.id.AffixDownloadProgressValue); String identityName = affix.getAffixId() + affix.getAffixName(); String key = identityName.substring(0, identityName.lastIndexOf(".")); String affixAbspath = affixShared.getString(key, null); if(affixAbspath != null) { mViewHolder.mAffixName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.result_ok, 0, 0, 0); mViewHolder.mButton.setText(R.string.open); mViewHolder.mButton.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.icon_open_file, 0); mViewHolder.isOpen = true; } mViewHolder.mAffixName.setText(affix.getAffixName()); mViewHolder.mButton.setTag(mViewHolder); mViewHolder.mButton.setOnClickListener(this); mViewGroup.addView(convertView); } } @Override public void onClick(View v) { Object object = v.getTag(); if(object instanceof ViewHolder) { ViewHolder mViewHolder = (ViewHolder) object; if(mViewHolder.isOpen) { AffixInfoBean affix = mViewHolder.affix; String key = affix.getAffixId() + affix.getAffixName(); String affixAbspath = affixShared.getString(key.substring(0, key.lastIndexOf(".")), ""); File file = new File(affixAbspath); if(!file.exists()) { mViewHolder.mButton.setText(R.string.redownload); mViewHolder.mButton.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.icon_download_ics, 0); mViewHolder.mAffixName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.attitude_falseinfo_icon, 0, 0, 0); mViewUtil.showAnimView(mViewHolder.mNotfoundFileErrormsg); mViewHolder.isOpen = false; } else switch(locationDateProcess.openFile(affixAbspath)) { // 成功打开 case 0: break; // 没有找到被打开的文件 case -1: break; // 没有找到对应的查看编辑器 case -2: App.makeText(context, R.string.find_no_editor); break; } } else if(!threadService.isAlive()) { threadService.setTag(mViewHolder); threadService.start(); } else App.makeText(context, R.string.please_wait); } } @Override public void onRun(Handler mHandler) { ViewHolder mViewHolder = (ViewHolder) threadService.getTag(); String fileName = mViewHolder.affix.getAffixName(); String downloadUrl = mViewHolder.affix.getDownloadUrl(); locationDateProcess.download(mHandler, fileName, downloadUrl); } @Override public void onResult(Message msg) { ViewHolder mViewHolder = (ViewHolder) threadService.getTag(); Bundle data = msg.getData(); int filesize = data.getInt("FILE_SIZE"); switch(msg.what) { // 下载成功 case 0: mViewHolder.mProgressBar.setProgress(filesize); mViewHolder.mDownloadProgressValue.setText(R.string.download_ok); mViewHolder.mAffixName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.result_ok, 0, 0, 0); mViewHolder.mButton.setText(R.string.open); mViewHolder.mButton.setEnabled(true); mViewHolder.mButton.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.icon_open_file, 0); mViewHolder.isOpen = true; String filePath = data.getString("FILE_CACHE_PATH"); Editor editor = affixShared.edit(); String key = mViewHolder.affix.getAffixId() + mViewHolder.affix.getAffixName(); editor.putString(key.substring(0, key.lastIndexOf(".")), filePath); editor.commit(); break; // 开始下载 case 1: mViewUtil.hideAnimView(mViewHolder.mNotfoundFileErrormsg, false); mViewUtil.showAnimView(mViewHolder.mDownloadProgressPanel); mViewHolder.mAffixName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon_download_manage_downloading, 0, 0, 0); mViewHolder.mProgressBar.setMax(filesize); mViewHolder.mDownloadProgressValue.setText(R.string.start_download); mViewHolder.mButton.setText(R.string.downloading); mViewHolder.mButton.setEnabled(false); break; // 正在下载 case 2: int downProgress = data.getInt("DOWN_PROGRESS"); int progress = (int) ((((float) downProgress) / ((float) filesize)) * 100); mViewHolder.mProgressBar.setProgress(downProgress); mViewHolder.mDownloadProgressValue.setText(progress + "%"); break; // 下载失败 case -1: mViewHolder.mAffixName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon_download_manage_fail, 0, 0, 0); mViewHolder.mDownloadProgressValue.setText(R.string.download_failed); mViewHolder.mButton.setText(R.string.retry); mViewHolder.mButton.setEnabled(true); mViewHolder.isOpen = false; break; // 文件已存在 case -2: mViewUtil.hideAnimView(mViewHolder.mDownloadProgressPanel, false); mViewHolder.mAffixName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.result_ok, 0, 0, 0); mViewHolder.mButton.setText(R.string.open); mViewHolder.mButton.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.icon_open_file, 0); mViewHolder.mButton.setEnabled(true); mViewHolder.isOpen = true; String haveFilePath = data.getString("FILE_CACHE_PATH"); Editor haveEditor = affixShared.edit(); String haveKey = mViewHolder.affix.getAffixId() + mViewHolder.affix.getAffixName(); haveEditor.putString(haveKey.substring(0, haveKey.lastIndexOf(".")), haveFilePath); haveEditor.commit(); App.makeText(context, R.string.file_already_exists); break; // 创建文件失败 case -3: mViewUtil.hideAnimView(mViewHolder.mDownloadProgressPanel, false); App.makeText(context, R.string.download_failed); break; } } private final class ViewHolder { private TextView mAffixName; private TextView mNotfoundFileErrormsg; private Button mButton; private RelativeLayout mDownloadProgressPanel; private ProgressBar mProgressBar; private TextView mDownloadProgressValue; private boolean isOpen; private AffixInfoBean affix; } }
类中所用到的其他相关类和方法:
1,ThreadService.java
import android.os.Handler; import android.os.Message; import com.hwttnet.oa.mobile.listener.OnThreadListener; /** * 服务于整个程序中所有耗时的操作,调用{@link #start()}方法即可将耗时的程序转入新线程中执行 * <P> * <I>线程执行方法不保证线程安全和数据传输绝对正常</I> * <P> * 该类不可被继承 * <HR> * 作者:孙博 * <P> * 时间:2012-10-18 下午3:42:55 * <P> * 电子邮件:[email protected] * <P> * QQ:497733379 * <P> * Gmail : [email protected] */ public final class ThreadService { private Thread thread; private Object tag; private OnThreadListener onThreadListener; private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (onThreadListener != null) onThreadListener.onResult(msg); } }; /** * 开启一个新的线程来执行一些耗时的操作 * <P> * 注意:<I>在调用该方法之前应该先为其设置线程运行监听器: * <P> * {@link #setOnThreadListener(OnThreadListener)} </I> */ public void start() { thread = new Thread() { @Override public void run() { if (onThreadListener != null) onThreadListener.onRun(mHandler); } }; thread.start(); } /** * 检测线程是否处于活动状态 * * @return 如果是活动状态,返回{@code true},否则返回{@code false} */ public boolean isAlive() { if (thread != null) return thread.isAlive(); return false; } /** * 为当前执行的线程设置运行时监听器以实时捕捉线程运行时到运行结束的过程 * * @param onThreadListener * 定义了线程运行时到运行结束的过程的监听器对象 */ public void setOnThreadListener(OnThreadListener onThreadListener) { this.onThreadListener = onThreadListener; } public Object getTag() { return tag; } public void setTag(Object tag) { this.tag = tag; } }
2,OnThreadListener.java
import android.os.Handler; import android.os.Message; /** * 线程调用时的回调接口,该接口中定义了线程运行时和结束后的回调方法 * <HR> * 作者:孙博 * <P> * 时间:2012-10-18 下午2:48:11 * <P> * 电子邮件:[email protected] * <P> * QQ:497733379 * <P> * Gmail : [email protected] */ public interface OnThreadListener { /** * 监听线程开始后的运行时状态,可在该方法中执行需要线程来操作的程序 * * @param mHandler * 已实例化且做好在线程中发送消息的对象 */ public void onRun(Handler mHandler); /** * 监听线程在结束后的状态,可在该方法中执行线程结束后需要操作的程序 * * @param msg * 在线程运行时得到的一个装载着消息内容的消息对象 */ public void onResult(Message msg); }
3,LocationDataProcess.java
import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedHashMap; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.res.Resources; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import com.hwttnet.oa.mobile.aas.R; import com.hwttnet.oa.mobile.app.App; /** * 本类包含了用于处理本地数据的基本方法: * <UL> * <LI>记录并获取程序中每个列表刷新的时间</LI> * </UL> * <HR> * 作者:孙博 * <P> * 时间:2012-10-18 上午11:29:49 * <P> * 电子邮件:[email protected] * <P> * QQ:497733379 * <P> * Gmail : [email protected] * */ public class LocationDataProcess { private final Context context; /** * @param context * 正在运行时的程序上下文对象 */ public LocationDataProcess(Context context) { this.context = context; } /** * 从网络中下载文件 * * <PRE> * Message msg = mHandler.obtainMessage(); * msg.what = msgWhat; // -1:失败;-2:文件已存在;-3:新文件创建失败;0:成功;1:开始下载;2:下载过程中 * Bundle data = msg.getData(); * data.putInt("<B>FILE_SIZE</B>", fileSize); * data.putInt("<B>DOWN_PROGRESS</B>", downProgress); * data.putString("<B>FILE_CACHE_PATH</B>", imageFilePath); * mHandler.sendMessage(msg); * </PRE> * * @param mHandler * 处理实时跟踪下载中向主线程发送的消息队列,一个已经被实例化的消息处理对象 * @param fileName * 要下载的文件标准名称,含后缀 * @param downloadUrl * 一个标准的网络文件{@code HTTP}地址 * @throws IOException * 如果网络异常或读取图片流出现问题,则抛出该异常 */ public void download(Handler mHandler, String fileName, String downloadUrl) { if (null == mHandler || null == downloadUrl) { this.sendMessage(mHandler, -1, 0, 0, null); return; } try { int downProgress = 0; URL url = new URL(downloadUrl); URLConnection connection = url.openConnection(); connection.setConnectTimeout(1000 * 30); connection.connect(); InputStream inputStream = connection.getInputStream(); int fileSize = connection.getContentLength(); if (fileSize < 1 || null == inputStream) this.sendMessage(mHandler, -1, fileSize, downProgress, null); else { this.sendMessage(mHandler, 1, fileSize, downProgress, null); File downloadFolder = new File(App.AFFIXSTORAGEPATH); if (!downloadFolder.exists()) downloadFolder.mkdirs(); File downloadFile = new File(downloadFolder.getAbsolutePath() + "/" + fileName); if (downloadFile.exists()) this.sendMessage(mHandler, -2, fileSize, downProgress, downloadFile.getAbsolutePath()); else if (downloadFile.createNewFile()) { byte[] buffer = new byte[1024 * 8]; int length = -1; BufferedOutputStream bufferOutStream = new BufferedOutputStream(new FileOutputStream(downloadFile)); while ((length = inputStream.read(buffer)) != -1) { bufferOutStream.write(buffer, 0, length); downProgress += length; this.sendMessage(mHandler, 2, fileSize, downProgress, downloadFile.getAbsolutePath()); } bufferOutStream.flush(); bufferOutStream.close(); inputStream.close(); this.sendMessage(mHandler, 0, fileSize, downProgress, downloadFile.getAbsolutePath()); } else this.sendMessage(mHandler, -3, fileSize, downProgress, null); } // 异常捕捉应该更详细 } catch (IOException e) { e.printStackTrace(); this.sendMessage(mHandler, -1, 0, 0, null); } } private void sendMessage(Handler mHandler, int msgWhat, int fileSize, int downProgress, String imageFilePath) { Message msg = mHandler.obtainMessage(); msg.what = msgWhat; Bundle data = msg.getData(); data.putInt("FILE_SIZE", fileSize); data.putInt("DOWN_PROGRESS", downProgress); data.putString("FILE_CACHE_PATH", imageFilePath); mHandler.sendMessage(msg); } /** * 根据指定的文件路径自动在系统中寻找与之对应的编辑器并打开该文件 * <P> * 支持共计38种不同后缀的文件,主要可被分类为: * * @param filePath * 一个有效的文件绝对路径 * @return 返回一个打开时的状态,具体如下: * <UL> * <LI>0:表示成功打开</LI> * <LI>-1:表示无法找到被打开的文件</LI> * <LI>-2:表示无法找到打开该文件的相关编辑器</LI> * </UL> */ public int openFile(String filePath) { File openFile = new File(filePath); if (!openFile.exists()) return -1; int openStauts = 0; String filename = openFile.getName(); String suffixName = filename.substring(filename.lastIndexOf("."), filename.length()); try { Resources r = context.getResources(); String[] officEndingNames = r.getStringArray(R.array.FILEENDINGOFFIC); for(String endingName : officEndingNames) if(suffixName.equals(endingName)) context.startActivity(this.getDefaultFileIntent(openFile)); String[] mediaEndingNames = r.getStringArray(R.array.FILENDINGMEDIA); for(String endingName : mediaEndingNames) if(suffixName.equals(endingName)) context.startActivity(this.getMediaFileIntent(openFile)); String[] htmlEndingNames = r.getStringArray(R.array.FILEENDINGHTML); for(String endingName : htmlEndingNames) if(suffixName.equals(endingName)) context.startActivity(this.getHtmlFileIntent(openFile)); String[] packEndingNames = r.getStringArray(R.array.FILEENDINGPACK); for(String endingName : packEndingNames) if(suffixName.equals(endingName)) context.startActivity(this.getPackFileIntent(openFile)); } catch (ActivityNotFoundException e) { e.printStackTrace(); openStauts = -2; } return openStauts; } private Intent getDefaultFileIntent(File defaultFile) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Uri uri = Uri.fromFile(defaultFile); String filename = defaultFile.getName(); String suffixName = filename.substring(filename.lastIndexOf("."), filename.length()); intent.setDataAndType(uri, DT.get(suffixName)); return intent; } private Intent getHtmlFileIntent(File htmlFile) { Uri uri = Uri.parse(htmlFile.toString()).buildUpon().encodedAuthority("com.android.htmlfileprovider").scheme("content").encodedPath(htmlFile.toString()).build(); Intent intent = new Intent(Intent.ACTION_VIEW); String filename = htmlFile.getName(); String suffixName = filename.substring(filename.lastIndexOf("."), filename.length()); intent.setDataAndType(uri, DT.get(suffixName)); return intent; } private Intent getMediaFileIntent(File audioFile) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtra("oneshot", 0); intent.putExtra("configchange", 0); Uri uri = Uri.fromFile(audioFile); String filename = audioFile.getName(); String suffixName = filename.substring(filename.lastIndexOf("."), filename.length()); intent.setDataAndType(uri, DT.get(suffixName)); return intent; } private Intent getPackFileIntent(File packFile) { Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setAction(android.content.Intent.ACTION_VIEW); Uri uri = Uri.fromFile(packFile); String filename = packFile.getName(); String suffixName = filename.substring(filename.lastIndexOf("."), filename.length()); intent.setDataAndType(uri, DT.get(suffixName)); return intent; } private final LinkedHashMap<String, String> DT = new LinkedHashMap<String, String>(); { // 图片 DT.put(".png", "image/*"); DT.put(".gif", "image/*"); DT.put(".jpg", "image/*"); DT.put(".jpeg", "image/*"); DT.put(".bmp", "image/*"); // 音频 DT.put(".mp3", "audio/*"); DT.put(".wav", "audio/*"); DT.put(".ogg", "audio/*"); DT.put(".midi", "audio/*"); // 视频 DT.put(".mp4", "video/*"); DT.put(".rmvb", "video/*"); DT.put(".avi", "video/*"); DT.put(".flv", "video/*"); // 办公 DT.put(".ppt", "application/vnd.ms-powerpoint"); DT.put(".pptx", "application/vnd.ms-powerpoint"); DT.put(".xls", "application/vnd.ms-excel"); DT.put(".xlsx", "application/vnd.ms-excel"); DT.put(".doc", "application/msword"); DT.put(".docx", "application/msword"); DT.put(".txt", "text/plain"); DT.put(".java", "text/plain"); DT.put(".c", "text/plain"); DT.put(".cpp", "text/plain"); DT.put(".py", "text/plain"); DT.put(".xml", "text/plain"); DT.put(".json", "text/plain"); DT.put(".log", "text/plain"); DT.put(".pdf", "application/pdf"); // 浏览器 DT.put(".htm", "text/html"); DT.put(".html", "text/html"); DT.put(".php", "text/html"); DT.put(".jsp", "text/html"); // 文件包 DT.put(".jar", "application/vnd.android.package-archive"); DT.put(".zip", "application/vnd.android.package-archive"); DT.put(".rar", "application/vnd.android.package-archive"); DT.put(".gz", "application/vnd.android.package-archive"); DT.put(".apk", "application/vnd.android.package-archive"); DT.put(".img", "application/vnd.android.package-archive"); } }
4,ViewUtil.java
import android.content.Context; import android.os.Handler; import android.view.View; import android.view.animation.AnimationUtils; /** * 提供界面中有关控件操作的所有相关方法 * * <HR> * 作者:孙博 * <P> * 时间:2012-10-18 下午2:25:13 * <P> * 电子邮件:[email protected] * <P> * QQ:497733379 * <P> * Gmail : [email protected] * */ public final class ViewUtil { private final Context context; private View mView; public ViewUtil(Context context) { this.context = context; } /** * 检测判断界面中某一个控件是否正处于显示状态 * * @param view * 要检测的界面控件 * @return 如果是显示状态返回{@code true},否则返回{@code false} */ public boolean isShown(View view) { if (view.getVisibility() == View.VISIBLE) return true; return false; } /** * 显示一个在界面存在但已经隐藏的控件 * * @param view * 要显示的界面控件,该控件必须是从<CODE>{@link android.view.View}</CODE>派生而来 */ public void showView(View view) { if (!this.isShown(view)) view.setVisibility(View.VISIBLE); } /** * 以动画方式显示一个在界面存在但已经隐藏的控件 * * @param view * 要显示的界面控件,该控件必须是从<CODE>{@link android.view.View}</CODE>派生而来 */ public void showAnimView(View view) { if (!this.isShown(view)) { view.setAnimation(AnimationUtils.loadAnimation(context, android.R.anim.fade_in)); view.setVisibility(View.VISIBLE); } } /** * 以动画方式显示一个在界面存在但已经隐藏的控件 * * @param view * 要显示的界面控件,该控件必须是从<CODE>{@link android.view.View}</CODE>派生而来 * @param id * 指定控件显示时的动画来源 */ public void showAnimView(View view, int id) { if (!this.isShown(view)) { view.setAnimation(AnimationUtils.loadAnimation(context, id)); view.setVisibility(View.VISIBLE); } } /** * 隐藏一个正显示中的控件 * * @param view * 要隐藏的界面控件,该控件必须是从<CODE>{@link android.view.View}</CODE>派生而来 * @param isKeepSeat * 是否保留该控件之前的所在位置 */ public void hideView(View view, boolean isKeepSeat) { if (this.isShown(view)) if (isKeepSeat) view.setVisibility(View.INVISIBLE); else view.setVisibility(View.GONE); } /** * 以动画方式隐藏一个正显示中的控件 * * @param view * 要隐藏的界面控件,该控件必须是从<CODE>{@link android.view.View}</CODE>派生而来 * @param isKeepSeat * 是否保留该控件之前的所在位置 */ public void hideAnimView(View view, boolean isKeepSeat) { if (this.isShown(view)) { view.setAnimation(AnimationUtils.loadAnimation(context, android.R.anim.fade_out)); if (isKeepSeat) view.setVisibility(View.INVISIBLE); else view.setVisibility(View.GONE); } } /** * 以动画方式隐藏一个正显示中的控件 * * @param view * 要隐藏的界面控件,该控件必须是从<CODE>{@link android.view.View}</CODE>派生而来 * @param id * 指定控件从屏幕中消失时的动画来源 * @param isKeepSeat * 是否保留该控件之前的所在位置 */ public void hideAnimView(View view, int id, boolean isKeepSeat) { if (this.isShown(view)) { view.setAnimation(AnimationUtils.loadAnimation(context, id)); if (isKeepSeat) view.setVisibility(View.INVISIBLE); else view.setVisibility(View.GONE); } } /** * 以动画形式显示一个控件,并设置该控件在屏幕中应该显示多长时间,在控件消失后,将不会再占用其在屏幕中的原有位置 * * @param view * 将要被显示的某个实例化控件对象 * @param displayTime * 指定控件将要在屏幕中显示的时间。<I>单位为毫秒</I> */ public void setTimeShowAnimView(View view, long displayTime) { this.mView = view; mHandler.removeCallbacks(runnable); this.showAnimView(view); mHandler.postDelayed(runnable, displayTime); } private final Handler mHandler = new Handler(); private final Runnable runnable = new Runnable() { @Override public void run() { hideAnimView(mView, false); } }; }
5,App.Shared.java
/** 记录本地一些基本的数据 */ public static final class Shared { /** 记录是否自动登录的标记 */ public static final String AUTOLOGIN = "AUTOLOGIN"; /** 记录不同的警告对话框是否要显示 */ public static final String WHETHERWARNING = "WHETHERWARNING"; /** 已下载附件记录文件名称 */ public static final String DOWNLOADAFFIXINFO = "AFFIXINFO"; }
6,AffixInfoBean.java
import java.io.Serializable; /** * 封装有附件全部相关信息的对应属性 * <HR> * 作者:孙博 * <P> * 时间:2012-11-26 下午3:41:46 * <P> * 电子邮件:[email protected] * <P> * QQ:497733379 * <P> * Gmail : [email protected] */ public class AffixInfoBean implements Serializable { private static final long serialVersionUID = -5184133590762842112L; private String affixId; private String affixName; private String downloadUrl; private String affixAffiliation; public String getAffixId() { return affixId; } public void setAffixId(String affixId) { this.affixId = affixId; } public String getAffixName() { return affixName; } public void setAffixName(String affixName) { this.affixName = affixName; } public String getDownloadUrl() { return downloadUrl; } public void setDownloadUrl(String downloadUrl) { this.downloadUrl = downloadUrl; } public String getAffixAffiliation() { return affixAffiliation; } public void setAffixAffiliation(String affixAffiliation) { this.affixAffiliation = affixAffiliation; } }
若有其他没有被上传的,还请见谅,因为太细了,需要什么,请回复,我会尽快的加上去!
3,最后就是调用,至于怎么调用,这里就不说了。
关于布局中所用到的相关资源:图片,文字信息等,在这里可以直接下载