Android Jamendo开源在线音乐播放器源码分析九 ViewFlipper及自定义布局控件的分析...

本文介绍如何使用ViewFlipper实现界面状态切换,并详细解析自定义ProgressBar与RemoteImageView组件的设计与实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在之前分析过这个ViewFlipper代码:

备注一:ViewFlipper

界面的最上面的mViewFlipper中包含了mGallery、mProgressBar、mFailureBar,刚开始以为最上面部分的显示是通过不同状态下设置View的visibility的VISIBLE,INVISIBLE, orGONE.来显示的,看完代码之后才知道是用的ViewFlipper这个空间实现的,代码显得更加清楚。

  1. <com.teleca.jamendo.util.FixedViewFlipper
  2. android:orientation="vertical"android:id="@+id/ViewFlipper"
  3. android:layout_width="fill_parent"android:layout_height="75dip"
  4. android:background="@drawable/gradient_dark_purple">
  5. <!--(0)Loading-->
  6. <LinearLayoutandroid:orientation="vertical"
  7. android:layout_width="fill_parent"android:layout_height="fill_parent"
  8. android:layout_marginLeft="15dip"android:gravity="left|center_vertical">
  9. <com.teleca.jamendo.widget.ProgressBar
  10. android:id="@+id/ProgressBar"android:layout_width="wrap_content"
  11. android:layout_height="wrap_content">
  12. </com.teleca.jamendo.widget.ProgressBar>
  13. </LinearLayout>
  14. <!--(1)Gallery-->
  15. <LinearLayoutandroid:orientation="vertical"
  16. android:layout_width="fill_parent"android:layout_height="fill_parent"
  17. android:gravity="center">
  18. <Galleryandroid:id="@+id/Gallery"android:layout_width="fill_parent"
  19. android:layout_height="wrap_content"android:spacing="0px"/>
  20. </LinearLayout>
  21. <!--(2)Failure-->
  22. <LinearLayoutandroid:orientation="vertical"
  23. android:layout_width="fill_parent"android:layout_height="fill_parent"
  24. android:layout_marginLeft="15dip"android:gravity="left|center_vertical">
  25. <com.teleca.jamendo.widget.FailureBar
  26. android:id="@+id/FailureBar"android:layout_width="wrap_content"
  27. android:layout_height="wrap_content">
  28. </com.teleca.jamendo.widget.FailureBar>
  29. </LinearLayout>
  30. </com.teleca.jamendo.util.FixedViewFlipper>
在onCreate()里面启动一个AsyncTask来加载,根据不同的结果决定显示ViewFlipper的哪部分内容

  1. privateclassNewsTaskextendsAsyncTask<Void,WSError,Album[]>{
  2. @Override
  3. publicvoidonPreExecute(){
  4. mViewFlipper.setDisplayedChild(0);
  5. mProgressBar.setText(R.string.loading_news);
  6. super.onPreExecute();
  7. }
  8. @Override
  9. publicAlbum[]doInBackground(Void...params){
  10. JamendoGet2Apiserver=newJamendoGet2ApiImpl();
  11. Album[]albums=null;
  12. try{
  13. albums=server.getPopularAlbumsWeek();
  14. }catch(JSONExceptione){
  15. e.printStackTrace();
  16. }catch(WSErrore){
  17. publishProgress(e);
  18. }
  19. returnalbums;
  20. }
  21. @Override
  22. publicvoidonPostExecute(Album[]albums){
  23. if(albums!=null&&albums.length>0){
  24. mViewFlipper.setDisplayedChild(1);
  25. ImageAdapteralbumsAdapter=newImageAdapter(HomeActivity.this);
  26. albumsAdapter.setList(albums);
  27. mGallery.setAdapter(albumsAdapter);
  28. mGallery.setOnItemClickListener(mGalleryListener);
  29. mGallery.setSelection(albums.length/2,true);//animatetocenter
  30. }else{
  31. mViewFlipper.setDisplayedChild(2);
  32. mFailureBar.setOnRetryListener(newOnClickListener(){
  33. @Override
  34. publicvoidonClick(Viewv){
  35. newNewsTask().execute((Void)null);
  36. }
  37. });
  38. mFailureBar.setText(R.string.connection_fail);
  39. }
  40. super.onPostExecute(albums);
  41. }
  42. @Override
  43. protectedvoidonProgressUpdate(WSError...values){
  44. Toast.makeText(HomeActivity.this,values[0].getMessage(),Toast.LENGTH_LONG).show();
  45. super.onProgressUpdate(values);
  46. }
  47. }
在这个AsyncTask中进行专辑的加载,在加载时onPreExecute()中mViewFlipper.setDisplayedChild(0);也就是上面xml代码中的(0) Loading部分,然后在doInBackground()中进行专辑的加载,当加载完之后onPostExecute(Album[] albums),然后根据加载专辑是否成功,选择相应的界面,是显示加载成功之后的(1) Gallery还是加载失败之后的(2) Failure。其实这里关键是这个空间ViewFlipper,在API中的解释是:

android.widget.ViewFlipper

SimpleViewAnimatorthat 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 downloadingof remote images。这个很好的获取图片的封装类,使我想显示图片的时候不用关心怎么从网络获取图片以及怎么生成图片,我只要将图片的URL地址传进来就可以了,获取完图片调用父类ImageView的setImageBitmap就可以显示想要的图片了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值