在之前分析过这个ViewFlipper代码:
备注一:ViewFlipper
界面的最上面的mViewFlipper中包含了mGallery、mProgressBar、mFailureBar,刚开始以为最上面部分的显示是通过不同状态下设置View的visibility 的VISIBLE, INVISIBLE, or GONE.来显示的,看完代码之后才知道是用的ViewFlipper这个空间实现的,代码显得更加清楚。
- <com.teleca.jamendo.util.FixedViewFlipper
- android:orientation="vertical" android:id="@+id/ViewFlipper"
- android:layout_width="fill_parent" android:layout_height="75dip"
- android:background="@drawable/gradient_dark_purple">
- <!-- (0) Loading -->
- <LinearLayout android:orientation="vertical"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- android:layout_marginLeft="15dip" android:gravity="left|center_vertical">
- <com.teleca.jamendo.widget.ProgressBar
- android:id="@+id/ProgressBar" android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- </com.teleca.jamendo.widget.ProgressBar>
- </LinearLayout>
- <!-- (1) Gallery -->
- <LinearLayout android:orientation="vertical"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- android:gravity="center">
- <Gallery android:id="@+id/Gallery" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:spacing="0px" />
- </LinearLayout>
- <!-- (2) Failure -->
- <LinearLayout android:orientation="vertical"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- android:layout_marginLeft="15dip" android:gravity="left|center_vertical">
- <com.teleca.jamendo.widget.FailureBar
- android:id="@+id/FailureBar" android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- </com.teleca.jamendo.widget.FailureBar>
- </LinearLayout>
- </com.teleca.jamendo.util.FixedViewFlipper>
- private class NewsTask extends AsyncTask<Void, WSError, Album[]> {
- @Override
- public void onPreExecute() {
- mViewFlipper.setDisplayedChild(0);
- mProgressBar.setText(R.string.loading_news);
- super.onPreExecute();
- }
- @Override
- public Album[] doInBackground(Void... params) {
- JamendoGet2Api server = new JamendoGet2ApiImpl();
- Album[] albums = null;
- try {
- albums = server.getPopularAlbumsWeek();
- } catch (JSONException e) {
- e.printStackTrace();
- } catch (WSError e){
- publishProgress(e);
- }
- return albums;
- }
- @Override
- public void onPostExecute(Album[] albums) {
- if(albums != null && albums.length > 0){
- mViewFlipper.setDisplayedChild(1);
- ImageAdapter albumsAdapter = new ImageAdapter(HomeActivity.this);
- albumsAdapter.setList(albums);
- mGallery.setAdapter(albumsAdapter);
- mGallery.setOnItemClickListener(mGalleryListener);
- mGallery.setSelection(albums.length/2, true); // animate to center
- } else {
- mViewFlipper.setDisplayedChild(2);
- mFailureBar.setOnRetryListener(new OnClickListener(){
- @Override
- public void onClick(View v) {
- new NewsTask().execute((Void)null);
- }
- });
- mFailureBar.setText(R.string.connection_fail);
- }
- super.onPostExecute(albums);
- }
- @Override
- protected void onProgressUpdate(WSError... values) {
- Toast.makeText(HomeActivity.this, values[0].getMessage(), Toast.LENGTH_LONG).show();
- super.onProgressUpdate(values);
- }
- }
android.widget.ViewFlipper
Simple ViewAnimator that will animate between two or more views that have been added to it. Only one child is shown at a time. If requested, can automatically flip between each child at a regular interval.
在com.teleca.jamendo.widget这个包中都是一些自定义的布局或者组件,这些布局和组件都是可以复用的。
ProgressBar

<!-- (0) Loading -->
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:layout_marginLeft="15dip" android:gravity="left|center_vertical">
<com.teleca.jamendo.widget.ProgressBar
android:id="@+id/ProgressBar" android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.teleca.jamendo.widget.ProgressBar>
</LinearLayout>
这个是当程序加载的时候显示的
/**
* Widget notifying user of ongoing action
*
* @author Lukasz Wisniewski
*/
public class ProgressBar extends LinearLayout {
protected TextView mTextView;
public ProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ProgressBar(Context context) {
super(context);
init();
}
/**
* Sharable code between constructors
*/
private void init(){
LayoutInflater.from(getContext()).inflate(R.layout.progress_bar, this);
mTextView = (TextView)findViewById(R.id.ProgressTextView);
}
/**
* Sets informative text
*
* @param resid
*/
public void setText(int resid){
mTextView.setText(resid);
}
}
progress_bar.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout android:layout_height="wrap_content"
android:minHeight="75dip" android:layout_width="fill_parent"
android:orientation="horizontal" android:gravity="center_vertical"
android:paddingLeft="13dip" android:paddingRight="13dip">
<ProgressBar android:id="@+id/ProgressBar"
android:layout_width="48dip" android:layout_height="48dip"></ProgressBar>
<LinearLayout android:layout_height="wrap_content"
android:paddingLeft="13dip" android:orientation="vertical"
android:layout_width="fill_parent">
<TextView android:id="@+id/ProgressTextView"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/loading" android:textSize="20dip" android:textColor="#ffffff"></TextView>
</LinearLayout>
</LinearLayout>
</merge>
我使用的时候只要mProgressBar.setText(R.string.loading_news);就可以设置他显示的文字信息
RemoteImageView
/**
* ImageView extended class allowing easy downloading
* of remote images
*
* @author Lukasz Wisniewski
*/
public class RemoteImageView extends ImageView{
/**
* Maximum number of unsuccesful tries of downloading an image
*/
private static int MAX_FAILURES = 3;
public RemoteImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public RemoteImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RemoteImageView(Context context) {
super(context);
init();
}
/**
* Sharable code between constructors
*/
private void init(){
}
/**
* Remote image location
*/
private String mUrl;
/**
* Currently successfully grabbed url
*/
private String mCurrentlyGrabbedUrl;
/**
* Remote image download failure counter
*/
private int mFailure;
/**
* Position of the image in the mListView
*/
private int mPosition;
/**
* ListView containg this image
*/
private ListView mListView;
/**
* Default image shown while loading or on url not found
*/
private Integer mDefaultImage;
/**
* Loads image from remote location
*
* @param url eg. http://random.com/abz.jpg
*/
public void setImageUrl(String url){
if(mListView == null && mCurrentlyGrabbedUrl != null && mCurrentlyGrabbedUrl.equals(url)){
// do nothing image is grabbed & loaded, we are golden
return;
}
if(mUrl != null && mUrl.equals(url)){
mFailure++;
if(mFailure > MAX_FAILURES){
Log.e(JamendoApplication.TAG, "Failed to download "+url+", falling back to default image");
loadDefaultImage();
return;
}
} else {
mUrl = url;
mFailure = 0;
}
ImageCache imageCache = JamendoApplication.getInstance().getImageCache();
if(imageCache.isCached(url)){
this.setImageBitmap(imageCache.get(url));
}
else {
try{
new DownloadTask().execute(url);
} catch (RejectedExecutionException e) {
// do nothing, just don't crash
}
}
}
/**
* Sets default local image shown when remote one is unavailable
*
* @param resid
*/
public void setDefaultImage(Integer resid){
mDefaultImage = resid;
}
/**
* Loads default image
*/
private void loadDefaultImage(){
if(mDefaultImage != null)
setImageResource(mDefaultImage);
}
/**
* Loads image from remote location in the ListView
*
* @param url eg. http://random.com/abz.jpg
* @param position ListView position where the image is nested
* @param listView ListView to which this image belongs
*/
public void setImageUrl(String url, int position, ListView listView){
mPosition = position;
mListView = listView;
setImageUrl(url);
}
/**
* Asynchronous image download task
*
* @author Lukasz Wisniewski
*/
class DownloadTask extends AsyncTask<String, Void, String>{
private String mTaskUrl;
@Override
public void onPreExecute() {
loadDefaultImage();
super.onPreExecute();
}
@Override
public String doInBackground(String... params) {
mTaskUrl = params[0];
InputStream stream = null;
URL imageUrl;
Bitmap bmp = null;
try {
imageUrl = new URL(mTaskUrl);
try {
stream = imageUrl.openStream();
bmp = BitmapFactory.decodeStream(stream);
try {
if(bmp != null){
JamendoApplication.getInstance().getImageCache().put(mTaskUrl, bmp);
Log.d(JamendoApplication.TAG, "Image cached "+mTaskUrl);
} else {
Log.w(JamendoApplication.TAG, "Failed to cache "+mTaskUrl);
}
} catch (NullPointerException e) {
Log.w(JamendoApplication.TAG, "Failed to cache "+mTaskUrl);
}
} catch (IOException e) {
Log.w(JamendoApplication.TAG, "Couldn't load bitmap from url: " + mTaskUrl);
} finally {
try {
if(stream != null){
stream.close();
}
} catch (IOException e) {}
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return mTaskUrl;
}
@Override
public void onPostExecute(String url) {
super.onPostExecute(url);
// target url may change while loading
if(!mTaskUrl.equals(mUrl))
return;
Bitmap bmp = JamendoApplication.getInstance().getImageCache().get(url);
if(bmp == null){
Log.w(JamendoApplication.TAG, "Trying again to download " + url);
RemoteImageView.this.setImageUrl(url);
} else {
// if image belongs to a list update it only if it's visible
if(mListView != null)
if(mPosition < mListView.getFirstVisiblePosition() || mPosition > mListView.getLastVisiblePosition())
return;
RemoteImageView.this.setImageBitmap(bmp);
mCurrentlyGrabbedUrl = url;
}
}
};
}
正如作者所说ImageView extended class allowing easy downloading of remote images。这个很好的获取图片的封装类,使我想显示图片的时候不用关心怎么从网络获取图片以及怎么生成图片,我只要将图片的URL地址传进来就可以了,获取完图片调用父类ImageView的setImageBitmap就可以显示想要的图片了。
本文详细介绍了如何利用ViewFlipper空间实现界面的动态切换,并通过自定义布局和控件如ProgressBar、FailureBar、RemoteImageView等优化加载体验和错误处理,特别关注于专辑加载过程中的界面展示逻辑。
2430

被折叠的 条评论
为什么被折叠?



