最近天天满课没有时间写,一次可以的时间我发现了一个很好的第三方库ninegridview,官网地址:https://github.com/jeasonlzy/NineGridView 是一个很好的九宫格显示库,类似QQ空间,微信朋友圈,微博主页等,展示图片的九宫格控件,自动根据图片的数量确定图片大小和控件大小,使用Adapter模式设置图片,对外提供接口回调,使用接口加载图片,支持任意的图片加载框架,如 Glide,ImageLoader,Fresco,xUtils3,Picasso 等,支持点击图片全屏预览大图
看到了这么好的库,当然要体验一波了,于是我就试着做了一个仿QQ空间的小程序,基于Bmob后端云数据库实现数据的存储和图像的上传,网站:https://www.bmob.cn/ ,基于ninegridview实现图片的显示,
接下来就是代码部分也是很简单首先在Application类中实现对ninegridview的初始化
public class App extends Application{
@Override
public void onCreate() {
super.onCreate();
NineGridView.setImageLoader(new GlideImageLoader());
ImagePicker imagePicker = ImagePicker.getInstance();
imagePicker.setImageLoader(new ImageLoader()); //设置图片加载器
imagePicker.setShowCamera(true); //显示拍照按钮
imagePicker.setCrop(true); //允许裁剪(单选才有效)
imagePicker.setSaveRectangle(true); //是否按矩形区域保存
imagePicker.setSelectLimit(9); //选中数量限制
imagePicker.setStyle(CropImageView.Style.RECTANGLE); //裁剪框的形状
imagePicker.setFocusWidth(800); //裁剪框的宽度。单位像素(圆形自动取宽高最小值)
imagePicker.setFocusHeight(800); //裁剪框的高度。单位像素(圆形自动取宽高最小值)
imagePicker.setOutPutX(1000);//保存文件的宽度。单位像素
imagePicker.setOutPutY(1000);//保存文件的高度。单位像素
}
private class GlideImageLoader implements NineGridView.ImageLoader {
@Override
public void onDisplayImage(Context context, ImageView imageView, String url) {
Glide.with(context).load(url)//
.placeholder(R.drawable.ic_default_image)//
.error(R.drawable.ic_default_image)//
.into(imageView);
}
@Override
public Bitmap getCacheImage(String url) {
return null;
}
}
}
接下来是自定义ScrollView,实现像QQ滑动标题栏颜色改变的效果
public class GradationScrollView extends ScrollView {
public interface ScrollViewListener {
void onScrollChanged(GradationScrollView scrollView, int x, int y,
int oldx, int oldy);
}
private ScrollViewListener scrollViewListener = null;
public GradationScrollView(Context context) {
super(context);
}
public GradationScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public GradationScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
}
接下来是布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.guet.andream.qqspace.MainActivity"
tools:showIn="@layout/activity_main">
<com.guet.andream.qqspace.VIew.GradationScrollView
android:id="@+id/scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="250dp">
<ImageView
android:id="@+id/backGroundImg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
android:scaleType="fitXY" />
<com.makeramen.roundedimageview.RoundedImageView
android:id="@+id/my_friend_icon"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="130dp"
app:riv_border_color="@color/colorPrimary"
app:riv_border_width="2dip"
app:riv_corner_radius="30dip"
android:src="@drawable/me"
app:riv_mutate_background="true"
app:riv_oval="true"
app:riv_tile_mode="clamp" />
<LinearLayout
android:id="@+id/menu_friend"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_alignParentBottom="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
style="@style/TextView"
android:text="相册" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
style="@style/TextView"
android:text="说说" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
style="@style/TextView"
android:text="个性化" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
style="@style/TextView"
android:text="小游戏" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
style="@style/TextView"
android:text="消息" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
<com.guet.andream.qqspace.VIew.NoScrollListview
android:id="@+id/spaceList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:divider="#dedede"
android:dividerHeight="18dp" />
</LinearLayout>
</com.guet.andream.qqspace.VIew.GradationScrollView>
<RelativeLayout
android:id="@+id/spaceTopChange"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="#003793c7">
<ImageView
android:id="@+id/spaceBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:src="@mipmap/left_arrow" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="好友动态"
android:textColor="@color/white"
android:textSize="17sp" />
<ImageView
android:id="@+id/spaceAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:src="@mipmap/add_space" />
</RelativeLayout>
</RelativeLayout>
然后就是MainActivity的代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener ,GradationScrollView.ScrollViewListener {
private ImageView backGroundImg;
private GradationScrollView scrollView;
private RelativeLayout spaceTopChange;
private int height;
private SpaceAdapter adapter;
private List<SpaceData> orders;
private NoScrollListview spaceList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bmob.initialize(this, "You Application Id");//在这里填写你在BOMB申请的ID
intiView();
initListeners();
}
@Override
protected void onResume() {
super.onResume();
intiData();
}
/**
* 初始化控件
*/
private void intiView() {
findViewById(R.id.spaceAdd).setOnClickListener(this);
findViewById(R.id.spaceBack).setOnClickListener(this);
spaceList= (NoScrollListview) findViewById(R.id.spaceList);
backGroundImg= (ImageView) findViewById(R.id.backGroundImg);
backGroundImg.setFocusable(true);
backGroundImg.setFocusableInTouchMode(true);
backGroundImg.requestFocus();
scrollView = (GradationScrollView) findViewById(R.id.scrollview);
spaceTopChange= (RelativeLayout) findViewById(R.id.spaceTopChange);
adapter=new SpaceAdapter(this,orders);
spaceList.setAdapter(adapter);
}
/**
* 查询数据
*/
private void intiData() {
BmobQuery<SpaceData> query =new BmobQuery<>();
query.order("-createdAt");
query.findObjects(new FindListener<SpaceData>() {
@Override
public void done(List<SpaceData> list, BmobException e) {
if(e==null){
orders=list;
adapter.addOrder(orders);
adapter.notifyDataSetChanged();
}
}
});
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.spaceAdd:
startActivity(new Intent(this,PublishActivity.class));
break;
case R.id.spaceBack:
finish();
break;
}
}
/**
* 获取顶部图片高度后,设置滚动监听
*/
private void initListeners() {
ViewTreeObserver vto = backGroundImg.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
spaceTopChange.getViewTreeObserver().removeGlobalOnLayoutListener(
this);
height = backGroundImg.getHeight();
scrollView.setScrollViewListener(MainActivity.this);
}
});
}
/**
* 滑动监听
* 根据滑动的距离动态改变标题栏颜色
*/
@Override
public void onScrollChanged(GradationScrollView scrollView, int x, int y, int oldx, int oldy) {
if (y <= 0) { //设置标题的背景颜色
spaceTopChange.setBackgroundColor(Color.argb( 0, 144, 151, 166));
} else if (y > 0 && y <= height-10) { //滑动距离小于banner图的高度时,设置背景和字体颜色颜色透明度渐变
float scale = (float) y / height;
float alpha = (255 * scale);
spaceTopChange.setBackgroundColor(Color.argb((int) alpha, 130, 117, 140));
} else { //滑动到banner下面设置普通颜色
spaceTopChange.setBackgroundColor(Color.parseColor("#584f60"));
}
}
}
最后就是listview适配器代码
public class SpaceAdapter extends BaseAdapter {
private List<SpaceData> orders;
private Context context;
public SpaceAdapter(Context context, List<SpaceData> orders) {
this.context = context;
this.orders = orders;
}
public void addOrder(List<SpaceData> orders) {
this.orders = orders;
}
@Override
public int getCount() {
if (orders == null)
return 0;
else
return orders.size();
}
@Override
public Object getItem(int i) {
return orders.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.space_list, null);
holder = new ViewHolder();
holder.name = (TextView) view.findViewById(R.id.spaceListName);
holder.time = (TextView) view.findViewById(R.id.spaceListTime);
holder.say = (TextView) view.findViewById(R.id.spaceListSay);
holder.icon = (ImageView) view.findViewById(R.id.spaceListIcon);
holder.nineGrid = (NineGridView) view.findViewById(R.id.nineGrid);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
Picasso.with(context).load(orders.get(i).getSpaceIcon()).into(holder.icon);
String mySay = orders.get(i).getSpaceSay();
if (mySay == null || mySay.length() <= 0) {
holder.say.setVisibility(View.GONE);
} else {
holder.say.setVisibility(View.VISIBLE);
holder.say.setText(mySay);
}
holder.name.setText(orders.get(i).getSpaceName());
holder.time.setText(orders.get(i).getUpdatedAt());
if (orders.get(i).isHaveIcon()) {//判断是否有图片
ArrayList<ImageInfo> imageInfo = new ArrayList<>();
for (int j = 0; j < orders.get(i).getSpaceImgUrl().size(); j++) {
ImageInfo info = new ImageInfo();
info.setThumbnailUrl(orders.get(i).getSpaceImgUrl().get(j));
info.setBigImageUrl(orders.get(i).getSpaceImgUrl().get(j));
imageInfo.add(info);
}
holder.nineGrid.setAdapter(new NineGridViewClickAdapter(context, imageInfo));
} else {
holder.nineGrid.setVisibility(View.GONE);
}
return view;
}
private class ViewHolder {
private TextView name;
private TextView time;
private TextView say;
private ImageView icon;
private NineGridView nineGrid;
}
}
这样就完成了QQ空间的界面和发布,查看的功能了,关于点赞评论等等功能小伙伴们可以去尝试一下开发
接下来的是上传界面和代码设计,大家先看效果图,里面放一个图片按钮,点击添加图片,关于存放图片我是用GridView来显示的,选择图片采用的的第三方库:https://github.com/jeasonlzy/ImagePicker
接下来是代码部分,首先是布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_published_about"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ecebeb"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/publishedToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary">
<TextView
android:id="@+id/upload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="8dp"
android:background="#00000000"
android:scaleType="centerInside"
android:text="发表"
android:textColor="#fff"
android:textSize="20dp" />
</android.support.v7.widget.Toolbar>
<EditText
android:id="@+id/publishSay"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="@null"
android:hint="说点什么吧..." />
<GridView
android:id="@+id/publishGridView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="90dp"
android:horizontalSpacing="4dp"
android:numColumns="4"
android:verticalSpacing="5dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="26dp">
<ImageView
android:layout_width="42dp"
android:layout_height="32dp"
android:layout_gravity="center"
android:layout_marginLeft="20dp"
android:src="@drawable/myplace" />
<TextView
android:id="@+id/locationAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="15dp"
android:text="显示地点"
android:textSize="16sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#dedede" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:orientation="vertical"
android:visibility="gone"
android:id="@+id/unloadLayout"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_height="wrap_content">
<com.github.ybq.android.spinkit.SpinKitView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/spin_kit"
style="@style/SpinKitView.Large.Circle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:SpinKit_Color="@color/colorAccent" />
<TextView
android:layout_width="wrap_content"
android:textColor="@color/colorAccent"
android:textSize="18sp"
android:text="发表中..."
android:layout_marginTop="10dp"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
接下来是activity的代码
public class PublishActivity extends AppCompatActivity {
private EditText publishSay;
private GridView publishGridView;
private GridAdapter gridAdapter;
private TextView upload;
private int size = 0;
private String mySay;
private LinearLayout unloadLayout;
private ArrayList<ImageItem> imageItems;
private final int UNLOAD_OK=0x110;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_publish);
Toolbar toolbar = (Toolbar) findViewById(R.id.publishedToolbar);
toolbar.setTitle("");
setSupportActionBar(toolbar);
toolbar.setNavigationIcon(R.mipmap.left_arrow);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
intiView();
}
//上传完成取消加载动画
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case UNLOAD_OK:
unloadLayout.setVisibility(View.GONE);
break;
}
}
};
private void intiView() {
publishSay= (EditText) findViewById(R.id.publishSay);
upload= (TextView) findViewById(R.id.upload);
//设置加载动画
unloadLayout= (LinearLayout) findViewById(R.id.unloadLayout);
ProgressBar progressBar = (ProgressBar)findViewById(R.id.spin_kit);
FadingCircle doubleBounce = new FadingCircle();
progressBar.setIndeterminateDrawable(doubleBounce);
publishGridView= (GridView) findViewById(R.id.publishGridView);
gridAdapter = new GridAdapter();
publishGridView.setAdapter(gridAdapter);
findViewById(R.id.upload).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mySay = publishSay.getText().toString();
publishSay.setText("");
if (mySay.length() < 1 && size == 0) {
showData("发表不能为空");
} else {
upload.setEnabled(false);
unloadLayout.setVisibility(View.VISIBLE);
new Thread() {
@Override
public void run() {
super.run();
upload_database();
}
}.start();
}
}
});
}
/**
* 上传函数
*/
private void upload_database() {
//隐藏软硬盘
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
final Message m=new Message();
m.what=UNLOAD_OK;
final SpaceData say = new SpaceData();
say.setSpaceSay(mySay);
say.setSpaceName("Andream");
say.setSpaceIcon("http://oekt4jwrq.bkt.clouddn.com/61e1899488617a31e9f93eed10e768b0.jpg");
if (size == 0) {
say.setHaveIcon(false);
say.save(new SaveListener<String>() {
@Override
public void done(String s, BmobException e) {
if(e==null)
{
finish();
handler.sendMessage(m);
}
}
});
return;
}
size = 0;
final String[] filePaths = new String[imageItems.size()];
for (int i = 0; i < imageItems.size(); i++) {
filePaths[i] = imageItems.get(i).path;
}
say.setHaveIcon(true);
BmobFile.uploadBatch(filePaths, new UploadBatchListener() {
@Override
public void onSuccess(List<BmobFile> list, List<String> list1) {
if (list1.size() == filePaths.length) {//如果数量相等,则代表文件全部上传完成
say.setSpaceImgUrl(list1);
say.save(new SaveListener<String>() {
@Override
public void done(String s, BmobException e) {
handler.sendMessage(m);
if (e == null) {
showData("上传成功");
finish();
}
}
});
}
}
@Override
public void onProgress(int i, int i1, int i2, int i3) {
}
@Override
public void onError(int i, String s) {
handler.sendMessage(m);
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == ImagePicker.RESULT_CODE_ITEMS) {
if (data != null && requestCode == 100) {
ArrayList<ImageInfo> imageInfo = new ArrayList<>();
imageItems = (ArrayList<ImageItem>) data.getSerializableExtra(ImagePicker.EXTRA_RESULT_ITEMS);
gridAdapter.notifyDataSetChanged();
size=imageItems.size();
} else {
showData("没有选择图片");
}
}
}
private class GridAdapter extends BaseAdapter {
public GridAdapter() {
}
@Override
public int getCount() {
if (imageItems == null)
return 1;
else
return imageItems.size()+1;
}
@Override
public Object getItem(int i) {
return imageItems.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(final int i, View view, ViewGroup viewGroup) {
GridAdapter.ViewHolder holder = null;
if (view == null) {
holder = new GridAdapter.ViewHolder();
view = LayoutInflater.from(PublishActivity.this).inflate(R.layout.grid_layout, null);
holder.image_voice = (ImageView) view.findViewById(R.id.gird_img);
view.setTag(holder);
} else {
holder = (GridAdapter.ViewHolder) view.getTag();
}
if (imageItems == null) {
holder.image_voice.setImageResource(R.drawable.add_icon);
} else {
if (i == imageItems.size()) {
holder.image_voice.setImageResource(R.drawable.add_icon);
} else {
File file = new File(imageItems.get(i).path);
if (file.exists()) {
Bitmap bm = BitmapFactory.decodeFile(imageItems.get(i).path);
holder.image_voice.setImageBitmap(CircleTransform.centerSquareScaleBitmap(bm,100));
}
}
}
holder.image_voice.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if ((imageItems != null && i == imageItems.size()) || imageItems == null) {
addImage();
}
}
});
return view;
}
class ViewHolder {
private ImageView image_voice;
}
}
/**
* 添加图片
*/
private void addImage() {
ImagePicker imagePicker = ImagePicker.getInstance();
imagePicker.setImageLoader(new ImageLoader());
imagePicker.setMultiMode(true); //多选
imagePicker.setShowCamera(true); //显示拍照按钮
imagePicker.setSelectLimit(6); //最多选择X张
imagePicker.setCrop(false); //不进行裁剪
Intent intent = new Intent(PublishActivity.this, ImageGridActivity.class);
startActivityForResult(intent, 100);
}
private void showData(String date){
Toast.makeText(this, date, Toast.LENGTH_SHORT).show();
}
}
最后是效果图