權聲明:本文為部落客原創文章,請尊重原創,轉載請标明位址。
轉載請注明出處: http://blog.csdn.net/sk719887916/article/details/40348873 作者skay:
最近參與了開發一款旅行APP,其中包含實時聊天和動态評論功能,終于耗時幾個月幾個夥伴完成了,今天就小結一下至于實時聊天功能如果使用者不多的情況可以scoket實作,如果使用者萬級就可以采用開源的smack + opnefile實作,也可以用mina開源+XMMP,至于怎麼搭建和實作,估計目前github上一搜一大把,至于即時通訊怕誤人子弟,暫且不做介紹,現就把實作的一個微信朋友圈的小功能介紹一下。
先上效果圖:
u
一拿到主流的UI需求,大緻分析下,需要我ListView嵌套Gridview,而gridView的行數也和圖檔總數有關系,是以通過個數我們可以動态設定條目的寬高,而點選圖檔放大我們可一跳轉到另一界面,圖檔左右滑動可以用viewpager實作,輕按兩下圖檔放大和手指縮放圖檔也可以用就監聽手勢進行不斷放大,對于安卓事件不熟悉的朋友可以直接使用一個著名的photoVIew開源項目,支援手勢縮放圖檔和滑動圖檔實作畫廊功能,也很好的解決了記憶體溢出問題。
一 配置ImageLoader
本項目中加載網絡圖檔我就直接使用imageLoader,但建議還是去看下源碼,因為開源項目本身自帶緩存機制,有很好的緩存技巧,有很多東西值得我們借鑒。其不僅可以加載本地圖檔(檔案path),也支援加載網絡圖檔(url),并且自帶防止記憶體溢出功能。
[java]
view plain
copy
print
?
- public class MyApplication extends Application {
- @Override
- public void onCreate() {
- super.onCreate();
- DisplayImageOptions defaultOptions = new DisplayImageOptions
- .Builder()
- .showImageForEmptyUri(R.drawable.empty_photo)
- .showImageOnFail(R.drawable.empty_photo)
- .cacheInMemory(true)
- .cacheOnDisc(true)
- .build();
- ImageLoaderConfiguration config = new ImageLoaderConfiguration
- .Builder(getApplicationContext())
- .defaultDisplayImageOptions(defaultOptions)
- .discCacheSize(50 * 1024 * 1024)//
- .discCacheFileCount(100)//緩存一百張圖檔
- .writeDebugLogs()
- .build();
- ImageLoader.getInstance().init(config);
- }
- }
二 準備主界面和需要的基礎類
1 Listadapter
[java]
view plain
copy
print
?
- public class FridListAdapter extends BaseAdapter{
- private ArrayList<MyBean> mList;
- private LayoutInflater mInflater;
- private Context mContext;
- public FridListAdapter(Context context,ArrayList<MyBean> list) {
- mInflater = LayoutInflater.from(context);
- mContext=context;
- this.mList=list;
- }
- @Override
- public int getCount() {
- return mList==null?0:mList.size();
- }
- @Override
- public MyBean getItem(int position) {
- return mList.get(position);
- }
- @Override
- public long getItemId(int position) {
- return getItem(position).id;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder;
- if (convertView == null) {
- holder = new ViewHolder();
- convertView = mInflater.inflate(R.layout.list_item, null);
- holder.avator=(ImageView)convertView.findViewById(R.id.avator);
- holder.name=(TextView)convertView.findViewById(R.id.name);
- holder.content = (TextView) convertView.findViewById(R.id.content);
- holder.gridView=(NoScrollGridView)convertView.findViewById(R.id.gridView);
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
- final MyBean bean = getItem(position);
- //加載網絡圖檔
- ImageLoader.getInstance().displayImage(bean.avator, holder.avator);
- holder.name.setText(bean.name);
- holder.content.setText(bean.content);
- if(bean.urls!=null&&bean.urls.length>0){
- holder.gridView.setVisibility(View.VISIBLE);
- holder.gridView.setAdapter(new DynamicGridAdapter(bean.urls, mContext));
- holder.gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- imageBrower(position,bean.urls);
- }
- });
- }else{
- holder.gridView.setVisibility(View.GONE);
- }
- return convertView;
- }
- private void imageBrower(int position, String[] urls) {
- Intent intent = new Intent(mContext, ImagePagerActivity.class);
- // 圖檔url,為了示範這裡使用常量,一般從資料庫中或網絡中擷取
- intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_URLS, urls);
- intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_INDEX, position);
- mContext.startActivity(intent);
- }
- // 優化listview
- private static class ViewHolder {
- public TextView name;
- public ImageView avator;
- TextView content;
- NoScrollGridView gridView;
- }
- }
2 主界面
實際項目中資料是資料是從伺服器擷取的,本次就隻将圖檔從網絡擷取,
[java]
view plain
copy
print
?
- public class MainActivity extends ListActivity {
- public static final String TAG = "MainActivity";
- private FridListAdapter mAdapter;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- new LoderDataTask().execute();
- }
- class LoderDataTask extends AsyncTask<Void, Void, MessageModle> {
- @Override
- protected MessageModle doInBackground(Void... params) {
- Gson gson = new Gson();
- MessageModle msg = gson.fromJson(getData(), MessageModle.class);
- return msg;
- }
- @Override
- protected void onPostExecute(MessageModle result) {
- mAdapter = new FridListAdapter(MainActivity.this, result.list);
- setListAdapter(mAdapter);
- }
- }
- private String getData() {
- // 模拟網絡擷取資料
- String json = "{\"code\":200,\"msg\":\"ok\",list:["
- + "{\"id\":110,\"avator\":\"http://img0.bdstatic.com/img/image/shouye/leimu/mingxing.jpg\",\"name\":\"趙薇\",\"content\":\"今天不開心!\",\"urls\":[]},"
- + "{\"id\":111,\"avator\":\"http://image.cnwest.com/attachement/jpg/site1/20110507/001372d8a36f0f2f4c953a.jpg\",\"name\":\"李晨\",\"content\":\"我們\","
- + " \"urls\":[\"http://guangdong.sinaimg.cn/2015/0530/U11307P693DT20150530094310.jpg\"]},"
- + "{\"id\":114,\"avator\":\"http://img.hexun.com/2009-05-01/117287830.jpg\",\"name\":\"小馬哥\",\"content\":\"今天淘寶了嗎\",\"urls\":["
- + "\"http://g.hiphotos.bdimg.com/album/s%3D680%3Bq%3D90/sign=ccd33b46d53f8794d7ff4b26e2207fc9/0d338744ebf81a4c0f993437d62a6059242da6a1.jpg\","
- + "\"http://f.hiphotos.bdimg.com/album/s%3D680%3Bq%3D90/sign=6b62f61bac6eddc422e7b7f309e0c7c0/6159252dd42a2834510deef55ab5c9ea14cebfa1.jpg\","
- + "\"http://g.hiphotos.bdimg.com/album/s%3D680%3Bq%3D90/sign=e58fb67bc8ea15ce45eee301863b4bce/a5c27d1ed21b0ef4fd6140a0dcc451da80cb3e47.jpg\","
- + "\"http://c.hiphotos.bdimg.com/album/s%3D680%3Bq%3D90/sign=cdab1512d000baa1be2c44b3772bc82f/91529822720e0cf3855c96050b46f21fbf09aaa1.jpg\"]},"
- + "{\"id\":112,\"avator\":\"http://img3.yxlady.com/yl/UploadFiles_5361/20150528/20150528050208705.jpg\",\"name\":\"鄧超\",\"content\":\"奔跑吧兄弟! 歡迎收看!\",\"urls\":[\"http://upload.cbg.cn/2015/0305/1425518659246.jpg\","
- + "\"http://www.people.com.cn/mediafile/pic/20150619/30/4179219540177204330.jpg\"]},"
- + "{\"id\":113,\"avator\":\"http://img4.imgtn.bdimg.com/it/u=945108765,1070109457&fm=21&gp=0.jpg\",\"name\":\"奧巴馬\",\"content\":\"holle\",\"urls\":[\"http://f.hiphotos.bdimg.com/album/s%3D680%3Bq%3D90/sign=6b62f61bac6eddc422e7b7f309e0c7c0/6159252dd42a2834510deef55ab5c9ea14cebfa1.jpg\",\"http://g.hiphotos.bdimg.com/album/s%3D680%3Bq%3D90/sign=e58fb67bc8ea15ce45eee301863b4bce/a5c27d1ed21b0ef4fd6140a0dcc451da80cb3e47.jpg\",\"http://c.hiphotos.bdimg.com/album/s%3D680%3Bq%3D90/sign=cdab1512d000baa1be2c44b3772bc82f/91529822720e0cf3855c96050b46f21fbf09aaa1.jpg\"]}]}";
- return json;
- }
3 GridView的Adapter
因為Listview的條目中包含Gridview,在這裡還需要為它建立atapter
由于adapter沒太多技術含量,是以重點部分列出,在這裡我們需要判斷下适配的資料眼總數,微信最大數是9張,顯示一張的時候,圖檔比較大,兩張的時候稍微減少,四張的時候兩列兩行和兩張的大小一緻,其他張數的時候都是三行三列的九宮格。
[java]
view plain
copy
print
?
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- MyGridViewHolder viewHolder;
- if (convertView == null) {
- viewHolder = new MyGridViewHolder();
- convertView = mLayoutInflater.inflate(R.layout.gridview_item,
- parent, false);
- viewHolder.imageView = (ImageView) convertView
- .findViewById(R.id.album_image);
- convertView.setTag(viewHolder);
- } else {
- viewHolder = (MyGridViewHolder) convertView.getTag();
- }
- String url = getItem(position);
- if (getCount() == 1) {
- viewHolder.imageView.setLayoutParams(new android.widget.AbsListView.LayoutParams(300, 250));
- }
- if (getCount() == 2 ||getCount() == 4) {
- viewHolder.imageView.setLayoutParams(new android.widget.AbsListView.LayoutParams(200, 200));
- }
- ImageLoader.getInstance().displayImage(url, viewHolder.imageView);
- return convertView;
- }
4 建立用于支援九宮格自定義的Gridview
[java]
view plain
copy
print
?
- public class NoScrollGridView extends GridView {
- public NoScrollGridView(Context context) {
- super(context);
- }
- public NoScrollGridView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int expandSpec = 0;
- int size = getAdapter().getCount();
- if (size == 1) {
- setNumColumns(1);
- }
- if ( size==2 || size == 4 ) {
- setNumColumns(2);
- }
- else {
- setNumColumns(3);
- }
- expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec,expandSpec );
- }
- }
三 點選圖檔後的基礎類
1 建立大圖檢視器viewpaer
[java]
view plain
copy
print
?
- public class ImagePagerActivity extends FragmentActivity {
- private static final String STATE_POSITION = "STATE_POSITION";
- public static final String EXTRA_IMAGE_INDEX = "image_index";
- public static final String EXTRA_IMAGE_URLS = "image_urls";
- private HackyViewPager mPager;
- private int pagerPosition;
- private TextView indicator;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.image_detail_pager);
- pagerPosition = getIntent().getIntExtra(EXTRA_IMAGE_INDEX, 0);
- String[] urls = getIntent().getStringArrayExtra(EXTRA_IMAGE_URLS);
- mPager = (HackyViewPager) findViewById(R.id.pager);
- ImagePagerAdapter mAdapter = new ImagePagerAdapter(
- getSupportFragmentManager(), urls);
- mPager.setAdapter(mAdapter);
- indicator = (TextView) findViewById(R.id.indicator);
- CharSequence text = getString(R.string.viewpager_indicator, 1, mPager
- .getAdapter().getCount());
- indicator.setText(text);
- // 更新下标
- mPager.setOnPageChangeListener(new OnPageChangeListener() {
- @Override
- public void onPageScrollStateChanged(int arg0) {
- }
- @Override
- public void onPageScrolled(int arg0, float arg1, int arg2) {
- }
- @Override
- public void onPageSelected(int arg0) {
- CharSequence text = getString(R.string.viewpager_indicator,
- arg0 + 1, mPager.getAdapter().getCount());
- indicator.setText(text);
- }
- });
- if (savedInstanceState != null) {
- pagerPosition = savedInstanceState.getInt(STATE_POSITION);
- }
- mPager.setCurrentItem(pagerPosition);
- }
- @Override
- public void onSaveInstanceState(Bundle outState) {
- outState.putInt(STATE_POSITION, mPager.getCurrentItem());
- }
- private class ImagePagerAdapter extends FragmentStatePagerAdapter {
- public String[] fileList;
- public ImagePagerAdapter(FragmentManager fm, String[] fileList) {
- super(fm);
- this.fileList = fileList;
- }
- @Override
- public int getCount() {
- return fileList == null ? 0 : fileList.length;
- }
- @Override
- public Fragment getItem(int position) {
- String url = fileList[position];
- return ImageDetailFragment.newInstance(url);
- }
- }
2 檢視大圖界面
轉載請注明出處: http://blog.csdn.net/sk719887916/article/details/40348873 作者skay:
[java] view plain copy print ?
- public class ImageDetailFragment extends Fragment {
- private String mImageUrl;
- private ImageView mImageView;
- private ProgressBar progressBar;
- private PhotoViewAttacher mAttacher;
- public static ImageDetailFragment newInstance(String imageUrl) {
- final ImageDetailFragment f = new ImageDetailFragment();
- final Bundle args = new Bundle();
- args.putString("url", imageUrl);
- f.setArguments(args);
- return f;
- }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mImageUrl = getArguments() != null ? getArguments().getString("url") : null;
- }
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- final View v = inflater.inflate(R.layout.image_detail_fragment, container, false);
- mImageView = (ImageView) v.findViewById(R.id.image);
- mAttacher = new PhotoViewAttacher(mImageView);
- mAttacher.setOnPhotoTapListener(new OnPhotoTapListener() {
- @Override
- public void onPhotoTap(View arg0, float arg1, float arg2) {
- getActivity().finish();
- }
- });
- progressBar = (ProgressBar) v.findViewById(R.id.loading);
- return v;
- }
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- ImageLoader.getInstance().displayImage(mImageUrl, mImageView, new SimpleImageLoadingListener() {
- @Override
- public void onLoadingStarted(String imageUri, View view) {
- progressBar.setVisibility(View.VISIBLE);
- }
- @Override
- public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
- String message = null;
- switch (failReason.getType()) {
- case IO_ERROR:
- message = "下載下傳錯誤";
- break;
- case DECODING_ERROR:
- message = "圖檔無法顯示";
- break;
- case NETWORK_DENIED:
- message = "網絡有問題,無法下載下傳";
- break;
- case OUT_OF_MEMORY:
- message = "圖檔太大無法顯示";
- break;
- case UNKNOWN:
- message = "未知的錯誤";
- break;
- }
- Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
- progressBar.setVisibility(View.GONE);
- }
- @Override
- public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
- progressBar.setVisibility(View.GONE);
- mAttacher.update();
- }
- });
- }
四 界面的頭像圓形
圓形頭像用主流的circleimageview.jar的架構,但是有興趣的朋友也可以自定義Imagview采用重寫onDrawI()畫圓形的方式将bitmap畫上去,由于此demo整體功能較複雜,是以使用第三方的東西,ListView條目布局如下:
[html]
view plain
copy
print
?
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="6dp" >
- <de.hdodenhof.circleimageview.CircleImageView
- android:id="@+id/avator"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:src="@drawable/empty_photo" />
- <TextView
- android:id="@+id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="10dp"
- android:layout_toRightOf="@id/avator"
- android:textColor="#576B95"
- android:textSize="16sp"
- android:text="name" />
- <TextView
- android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@+id/name"
- android:layout_marginLeft="10dp"
- android:textSize="12sp"
- android:layout_toRightOf="@id/avator"
- android:text="content" />
- <com.loveplusplus.demo.image.NoScrollGridView
- android:id="@+id/gridView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingTop="5dp"
- android:layout_below="@id/content"
- android:layout_marginLeft="10dp"
- android:layout_toRightOf="@id/avator"
- android:horizontalSpacing="1dp"
- android:numColumns="3"
- android:visibility="gone"
- android:verticalSpacing="1dp" />
- </RelativeLayout>
接下來我們還需要将主流的photoView.jar加入到工程中,
總結一下實作以上功能我們使用了第三的imagloader,支援手勢縮放的PhotoView,圓形圖像的circleimageView,熟悉安卓view繪制機制加載過程,事件傳遞和分發的朋友是不需要第三方開源項目的支援的,但是對于入門不久的同學,學會怎樣使用開源架構就可以,但是想要提高開源項目的的核心還是需要了解的,歡迎閱讀
運作效果圖:
有興趣的朋友建議閱讀下:
安卓事件機制(一)和上篇關于View的博文。謝謝交流和分享。