安卓 仿微信朋友圈选择图片,拍照,大图预览,删除等功能
来源:互联网 发布:测试性能的软件 编辑:程序博客网 时间:2024/05/11 17:28
首先看一下基本的效果图:
1,GridView和加号的实现,直接上代码
布局文件:
<GridViewandroid:id="@+id/gv_kinder_image"android:layout_width="fill_parent"android:layout_height="wrap_content"android:horizontalSpacing="5.0dip"android:listSelector="@null"android:numColumns="4"android:scrollbars="none"android:layout_margin="10dp"android:verticalSpacing="5.0dip" />
这个没有什么可说的,看一下具体的适配器怎么写吧
public class ImageAdapter extends BaseAdapter { private Context mContext; private ArrayList<String> photos;//返回的本地图片的地址 // Constructor public ImageAdapter(Context c, ArrayList<String> mPhotos) { mContext = c; photos = mPhotos; idType = type; } public int getCount() { return photos.size() + 1;//返回数目加1为了将”加号“添加到Gridview上 } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { holder = new ViewHolder(); convertView = LayoutInflater.from(XddApp.context).inflate(R.layout.grid_item_select , parent, false); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.imageView = (ImageView) convertView.findViewById(R.id.iv_kinder_image); holder.imageView1 = (ImageView) convertView.findViewById(R.id.iv_kinder_image1); if (position < photos.size()) { Glide.with(XddApp.context) .load(new File(photos.get(position))) .fitCenter() .into(holder.imageView); holder.imageView.setVisibility(View.VISIBLE); holder.imageView1.setVisibility(View.GONE); } else { // 手动添加一个Item(加号) holder.imageView.setVisibility(View.GONE); holder.imageView1.setVisibility(View.VISIBLE); holder.imageView1.setOnClickListener(new View.OnClickListener() {//设置点击事件跳转选择照片的界面 @Override public void onClick(View v) { Intent intent = new Intent(mContext,GridPhonePhotoActivity.class); intent.putStringArrayListExtra("photos", photos); mContext.startActivityForResult(intent, idType); } }); } return convertView; } static class ViewHolder { public ImageView imageView; public ImageView imageView1; }}
选择完照片需要再onactivityresult返回刷新
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode==1000&&resultCode==RESULT_OK&&data.hasExtra("photos")){ ArrayList<String> photos = data.getStringArrayListExtra("photos"); mPhotos.clear(); for (int i = 0; i < photos.size(); i++) { mPhotos.add(photos.get(i)); } adapter.notifyDataSetChanged(); }
2,接下来是图片选择的界面(此处用imageloader加载(加载本地图片会很快),以及调用系统照相机)
1,布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="44dp"> <TextView android:id="@+id/btn_cancel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="10dp" android:background="@android:color/transparent" android:padding="10dp" android:text="取消" android:textColor="#000000" android:textSize="16sp" /> <LinearLayout android:id="@+id/ll_next" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:orientation="horizontal"> <TextView android:id="@+id/img_count" android:layout_width="20dp" android:layout_height="20dp" android:layout_centerVertical="true" android:background="@drawable/point_red" android:gravity="center" android:textColor="#ffffff" android:textSize="14sp" /> <TextView android:id="@+id/btn_next" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="10dp" android:background="@android:color/transparent" android:gravity="center_vertical" android:paddingLeft="5dp" android:paddingRight="10dp" android:text="下一步" android:textColor="#000000" android:textSize="16sp" /> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="相机胶卷" android:textColor="#000000" android:textSize="20sp" /> </RelativeLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#f8f8f8" /> <GridView android:id="@+id/gv_img" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="10dp" android:horizontalSpacing="7dp" android:numColumns="4" android:orientation="horizontal" android:verticalSpacing="7dp"/></LinearLayout>
2,主要逻辑
/** * Created by mlb on 17/5/11. */public class GridPhonePhotoActivity extends BaseActivity { private List<ImageItem> mImgItems = new ArrayList<>(); private ArrayList<String> chooseImg = new ArrayList<>(); @InjectView(R.id.img_count) TextView mCount; @InjectView(R.id.btn_next) TextView mBtnNext; @InjectView(R.id.btn_cancel) TextView btnCancel; @InjectView(R.id.gv_img) GridView mGvImg; private ChooseimgAdapter adapter; private String path; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_grid_phone_photo); ButterKnife.inject(this); getData(); makeAdapter(); } private void makeAdapter() { adapter = new ChooseimgAdapter(); mGvImg.setAdapter(adapter); btnCancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); //将选择了的数据返回到上一界面 mBtnNext.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { chooseImg.clear(); if(getSelectCount()==0){ }else{ for(int i=0;i<mImgItems.size();i++){ if(mImgItems.get(i).isSelected){ chooseImg.add(mImgItems.get(i).sourcePath); } } Intent intent = getIntent(); intent.putStringArrayListExtra("photos",chooseImg); setResult(RESULT_OK,intent); finish(); } } }); setIsHasChoose(); } //获取已经选择了的照片数据 private void getData() { getSelectData(getIntent()); mImgItems.clear(); ArrayList<ImageFolderModel> allPhotos = Utils.getAllPhotos(); ImageFolderModel imageFolderModel = allPhotos.get(0); for (int i = 1; i < imageFolderModel.getImages().size(); i++) { ImageItem imageItem = new ImageItem(); String s = imageFolderModel.getImages().get(i); imageItem.sourcePath = s; if (chooseImg.contains(s)) { imageItem.isSelected = true; } else { imageItem.isSelected = false; } mImgItems.add(imageItem); } } private final int CODE_CAMERA_REQUEST = 0xa1; private class ChooseimgAdapter extends BaseAdapter { private ImageLoader imageLoader = ImageLoader.getInstance(); private DisplayImageOptions options = new DisplayImageOptions.Builder() .cacheInMemory(true) // 设置下载的图片是否缓存在内存中 .cacheOnDisc(true) // 设置下载的图片是否缓存在SD卡中 .showStubImage(R.color.white) // 设置图片下载期间显示的图片 .showImageForEmptyUri(R.color.white) // 设置图片Uri为空或是错误的时候显示的图片 .showImageOnFail(R.color.white) // 设置图片加载或解码过程中发生错误显示的图片 .bitmapConfig(Bitmap.Config.ARGB_8888) .imageScaleType(ImageScaleType.IN_SAMPLE_INT) .build(); // 创建配置过的DisplayImageOption对象 @Override public int getCount() { return mImgItems.size() + 1; } @Override public Object getItem(int i) { return null; } @Override public long getItemId(int i) { return 0; } @Override public View getView(final int position, View convertView, ViewGroup viewGroup) { ViewHolder holder = null; if (convertView == null) { holder = new ViewHolder(); convertView = LayoutInflater.from(XddApp.context).inflate(R.layout.list_item_choose_multi_img , viewGroup, false); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.img = (ImageView) convertView.findViewById(R.id.item_img); holder.firstimg = (ImageView) convertView.findViewById(R.id.first_img); //调用系统相机 holder.cb = (ImageView) convertView.findViewById(R.id.cb);//是否被选中的对勾图片 if (position == 0) { holder.firstimg.setVisibility(View.VISIBLE); holder.img.setVisibility(View.GONE); holder.cb.setVisibility(View.GONE); } else { holder.firstimg.setVisibility(View.GONE); holder.img.setVisibility(View.VISIBLE); imageLoader.displayImage("file://" + mImgItems.get(position - 1).sourcePath, holder.img, options); holder.cb.setVisibility(View.VISIBLE); if (mImgItems.get(position - 1).isSelected) { holder.cb.setImageResource(R.drawable.check); } else { holder.cb.setImageResource(R.drawable.no_check); } holder.cb.setVisibility(View.VISIBLE); } //调用系统相机,拍照并返回 holder.firstimg.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { path = System.currentTimeMillis() + ".png"; Intent intentFromCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (Utils.hasSdcard()) { intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri .fromFile(new File(Environment .getExternalStorageDirectory(), path))); } startActivityForResult(intentFromCapture, CODE_CAMERA_REQUEST); } }); //进入大图轮播选择 或者取消选择 holder.img.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(XddApp.context, PhotoChooseSeeActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable("photos", (Serializable) mImgItems); intent.putExtras(bundle); intent.putExtra("position", position - 1); startActivityForResult(intent, 100); } }); final ViewHolder finalHolder = holder; holder.cb.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mImgItems.get(position - 1).isSelected) { mImgItems.get(position - 1).isSelected = false; } else { mImgItems.get(position - 1).isSelected = true; } if (mImgItems.get(position - 1).isSelected) { if (getSelectCount() > 9) { finalHolder.cb.setImageResource(R.drawable.no_check); mImgItems.get(position - 1).isSelected = false; SnackbarUtils.show(finalHolder.cb, "你最多只能选择9张照片"); } else { finalHolder.cb.setImageResource(R.drawable.check); mImgItems.get(position - 1).isSelected = true; } } else { finalHolder.cb.setImageResource(R.drawable.no_check); mImgItems.get(position - 1).isSelected = false; } int selectCount = getSelectCount(); if (selectCount > 0) { mCount.setText(selectCount + ""); mCount.setVisibility(View.VISIBLE); mBtnNext.setTextColor(Color.parseColor("#000000")); } else { mCount.setVisibility(View.GONE); mBtnNext.setTextColor(Color.parseColor("#999999")); } } }); return convertView; } class ViewHolder { public ImageView img; public ImageView firstimg; public ImageView cb; } } private int getSelectCount() { int count = 0; for (int i = 0; i < mImgItems.size(); i++) { if (mImgItems.get(i).isSelected) { count++; } } return count; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_CANCELED) { return; } if (requestCode == CODE_CAMERA_REQUEST && resultCode == RESULT_OK) { if (Utils.hasSdcard()) { File tempFile = new File( Environment.getExternalStorageDirectory(), path); ImageItem imageItem = new ImageItem(); imageItem.sourcePath = tempFile.getPath(); if (getSelectCount() >= 9) { imageItem.isSelected = false; } else { imageItem.isSelected = true; } mImgItems.add(0, imageItem); adapter.notifyDataSetChanged(); setIsHasChoose(); } else { SnackbarUtils.show(mCount, "您的手机没有SDCard!"); } } if (requestCode == 100 && resultCode == RESULT_OK) { getSelectData(data); adapter.notifyDataSetChanged(); setIsHasChoose(); } } private void setIsHasChoose(){ int selectCount = getSelectCount(); if (selectCount > 0) { mCount.setText(selectCount + ""); mCount.setVisibility(View.VISIBLE); mBtnNext.setTextColor(Color.parseColor("#000000")); } else { mCount.setVisibility(View.GONE); mBtnNext.setTextColor(Color.parseColor("#999999")); } } private void getSelectData(Intent data) { chooseImg.clear(); if (data.hasExtra("photos")) { ArrayList<String> photos = data.getStringArrayListExtra("photos"); chooseImg.addAll(photos); } for (int i = 0; i < mImgItems.size(); i++) { if (chooseImg.contains(mImgItems.get(i).sourcePath)) { mImgItems.get(i).isSelected = true; } else { mImgItems.get(i).isSelected = false; } } }}
大图界面选择或者取消选择
//本地相册图片大图显示页面public class PhotoChooseSeeActivity extends BaseActivity implements View.OnClickListener{ private ViewPager mVp; private ImageView mIvCancel; private ImageView mCb; private LinearLayout mLlok; private TextView mImgCount; private ArrayList<ImageItem> photos=new ArrayList<>(); private ArrayList<String> chooseImgs=new ArrayList<>(); private int photoPosition; private boolean isShow=true; private RelativeLayout mTop; private LinearLayout mBottom; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_photo_vp); initView(); } protected void initView() { List<ImageItem> datas = (List<ImageItem>) getIntent().getSerializableExtra("photos"); photos.addAll(datas); photoPosition = getIntent().getIntExtra("position", 0); mTop = (RelativeLayout) findViewById(R.id.rl_top); mBottom = (LinearLayout) findViewById(R.id.ll_bottom); mVp = (ViewPager) findViewById(R.id.vp); mIvCancel = (ImageView) findViewById(R.id.cancel); mCb = (ImageView) findViewById(R.id.cb); mLlok = (LinearLayout) findViewById(R.id.ll_ok); mImgCount = (TextView) findViewById(R.id.img_count); if(getSelectCount()==0){ mImgCount.setVisibility(View.GONE); }else{ mImgCount.setVisibility(View.VISIBLE); mImgCount.setText(getSelectCount()+""); } if(photos.get(photoPosition).isSelected){ mCb.setImageResource(R.drawable.check); }else{ mCb.setImageResource(R.drawable.no_check); } mIvCancel.setOnClickListener(this); mLlok.setOnClickListener(this); mVp.setAdapter(new PagerAdapter() { @Override public int getCount() { return photos.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, final int position) { ImageView view = new ImageView(XddApp.context); Glide.with(XddApp.context) .load(new File( photos.get(position).sourcePath)) .diskCacheStrategy(DiskCacheStrategy.SOURCE) .centerCrop() .fitCenter() .into(view); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(isShow){ isShow=false; mTop.setVisibility(View.GONE); mBottom.setVisibility(View.GONE); }else{ isShow=true; mTop.setVisibility(View.VISIBLE); mBottom.setVisibility(View.VISIBLE); } } }); container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } }); mVp.setCurrentItem(photoPosition); mCb.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(!photos.get(mVp.getCurrentItem()).isSelected){ if(getSelectCount()>=9){ SnackbarUtils.show(mCb,"你最多只能选择9张照片"); }else{ photos.get(mVp.getCurrentItem()).isSelected=true; mCb.setImageResource(R.drawable.check); } }else{ photos.get(mVp.getCurrentItem()).isSelected=false; mCb.setImageResource(R.drawable.no_check); } if(getSelectCount()==0){ mImgCount.setVisibility(View.GONE); }else{ mImgCount.setVisibility(View.VISIBLE); mImgCount.setText(getSelectCount()+""); } } }); mVp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if(photos.get(position).isSelected){ mCb.setImageResource(R.drawable.check); }else{ mCb.setImageResource(R.drawable.no_check); } } @Override public void onPageScrollStateChanged(int state) { } }); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.cancel: finish(); break; case R.id.ll_ok: //fanhui chooseImgs.clear(); if(getSelectCount()==0){ chooseImgs.add(photos.get(photoPosition).sourcePath); }else{ for(int i=0;i<photos.size();i++){ if(photos.get(i).isSelected){ chooseImgs.add(photos.get(i).sourcePath); } } } Intent intent = getIntent(); intent.putStringArrayListExtra("photos",chooseImgs); setResult(RESULT_OK,intent); finish(); } } private int getSelectCount(){ int selectCount=0; for(int i=0;i<photos.size();i++){ if(photos.get(i).isSelected){ selectCount++; } } return selectCount; }}
最后一步,点击已经选择的照片进入删除界面
public class ImageLookActivity extends BaseActivity { @InjectView(R.id.view_pager) ViewPager vp; @InjectView(R.id.rl_all) RelativeLayout rlAll; @InjectView(R.id.tv_return) TextView tvReturn; @InjectView(R.id.tv_number) TextView tvNumber; @InjectView(R.id.iv_delete) ImageView ivDelete; private ArrayList<String> photos; private int mPosition = 0; private boolean seleteType; private boolean isOpen = false; private MyImgViewPagerAdapetr adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_img_look); ButterKnife.inject(this); Bundle bundle = getIntent().getExtras(); photos = (ArrayList) bundle.getSerializable("photos"); mPosition = getIntent().getIntExtra("position", 0); seleteType = getIntent().getBooleanExtra("seleteType", false); LogUtils.e("seleteType", seleteType); if (seleteType) { rlAll.setVisibility(View.VISIBLE); tvNumber.setText((mPosition + 1) + "/" + photos.size()); isOpen = !isOpen; } else { rlAll.setVisibility(View.GONE); } setLookImg(); tvReturn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = getIntent(); intent.putStringArrayListExtra("photos", photos); setResult(RESULT_OK, intent); finish(); } }); ivDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new ActionSheetDialog(ImageLookActivity.this) .builder() .setCancelable(false) .setCanceledOnTouchOutside(false) .addSheetItem("删除", ActionSheetDialog.SheetItemColor.Blue, new ActionSheetDialog.OnSheetItemClickListener() { @Override public void onClick(int which) { mPosition = vp.getCurrentItem(); photos.remove(mPosition); if (photos.size() == 0) { Intent intent = getIntent(); intent.putStringArrayListExtra("photos", photos); setResult(RESULT_OK, intent); finish(); } else{ adapter.notifyDataSetChanged(); tvNumber.setText((mPosition == 0)?((mPosition + 1)+ "/" + photos.size()):(mPosition + "/" + photos.size())); } } }).show(); } }); } private void setLookImg() { adapter = new MyImgViewPagerAdapetr(); vp.setAdapter(adapter); vp.setCurrentItem(mPosition); vp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (seleteType) { rlAll.setVisibility(View.GONE); isOpen = !isOpen; } } @Override public void onPageSelected(int position) { if (seleteType) { tvNumber.setText((position + 1) + "/" + photos.size()); } } @Override public void onPageScrollStateChanged(int state) { if (seleteType) { rlAll.setVisibility(View.GONE); isOpen = !isOpen; } } }); } class MyImgViewPagerAdapetr extends PagerAdapter { @Override public int getCount() { return photos.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public int getItemPosition(Object object) { // 最简单解决 notifyDataSetChanged() 页面不刷新问题的方法 return POSITION_NONE; } @Override public Object instantiateItem(ViewGroup container, final int position) { ImageView view = new ImageView(XddApp.context); Glide.with(XddApp.context) .load(photos.get(position)) .fitCenter() .into(view); if (!seleteType) { view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); view.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { new ActionSheetDialog(ImageLookActivity.this) .builder() .setCancelable(false) .setCanceledOnTouchOutside(false) .addSheetItem("保存", ActionSheetDialog.SheetItemColor.Blue, new ActionSheetDialog.OnSheetItemClickListener() { @Override public void onClick(int which) { savePhoto(photos.get(position)); } }).show(); return true; } }); } else { view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { rlAll.setVisibility(isOpen?View.GONE:View.VISIBLE); isOpen = !isOpen; } }); } container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } } private void savePhoto(String url) { Glide.with(this).load(url).asBitmap().into(new SimpleTarget<Bitmap>() { @Override public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) { String path = "/mnt/sdcard/" + System.currentTimeMillis() + ".png"; File bitmapFile = new File(path); if (!bitmapFile.exists()) { try { bitmapFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } FileOutputStream fos = null; try { fos = new FileOutputStream(bitmapFile); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); runOnUiThread(new Runnable() { @Override public void run() { SnackbarUtils.show(vp, "你保存的样子最美"); } }); Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); Uri uri = Uri.fromFile(bitmapFile); intent.setData(uri); sendBroadcast(intent); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fos != null) { fos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }); //方法中设置asBitmap可以设置回调类型 }}
代码很容易看 就不一一注释了
第一次写博客,还希望多多指教。
阅读全文
0 0
- 安卓 仿微信朋友圈选择图片,拍照,大图预览,删除等功能
- 安卓选择图片上传功能【支持多选拍照预览等】
- Android 超高仿微信图片多选、单选,图片剪切,图片预览,拍照等功能
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等 .
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
- iOS Xcode原生项目集成Unity导出的工程
- 【如何快速的开发一个完整的iOS直播app】(编解码原理)
- order by 语句对null字段的默认排序
- 【Unity3D自学记录】VR插件CardboardSDKForUnity解析(一)
- C# 怎样通过ip和端口向一台设备发送指令
- 安卓 仿微信朋友圈选择图片,拍照,大图预览,删除等功能
- java回调机制
- 【如何快速的开发一个完整的iOS直播app】(点赞功能)
- 搭建ssm框架
- Git冲突:commit your changes or stash them before you can merge.
- 自定义控件之二阶贝塞尔曲线方法详解
- UML学习笔记之状态图
- 安装VirtualBox的时候遇到的问题
- Vue自定义动画和animate.css使用