Android Bmob之模仿朋友圈

基于Bmob实现浏览图片,可点击查看大图和双击、手势缩放图片。

效果图: 

列表采用Listview嵌套GridView,查看大图时使用ViewPager+PhotoView。

 

图片和文字的数据来源Bmob的Publish表上:

每个用户可发表文字或图片或图片+文字到Publish表中。

Publish表的结构:

内容包括用户名,用户发表帖子的内容(文字),用户发表帖子的时间,用户发表的图片,用户发了几张图(有这个变量后面处理图片会容易些)。

public class Publish  extends BmobObject {
    //用户名
    private String name;
    //用户发布帖子的内容
    private String message;
    //用户发布帖子的时间
    private String time;

    //用户最多能发9张图
    private List<BmobFile> picture;

    public List<BmobFile> getPicture() {
        return picture;
    }

    public void setPicture(List<BmobFile> picture) {
        this.picture = picture;
    }

    //上传多少张图片
    private int n;

    public int getN() {
        return n;
    }

    public void setN(int n) {
        this.n = n;
    }


    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

本文主要记录把图片和文字放在列表中,模仿朋友圈浏览信息的过程。

1、ListView中嵌套GridView实现布局

ListView的每个Item都要加载多张网络图片并且显示到屏幕中,Item中的每个GridView要显示多张图片,所以GridView要重写来决解宽高的问题,不然图片会显示不出来。

GridView重写:

  1、重写onMeasure方法来决解ListView中嵌套GridView图片显示不全的问题。

  2、GridView显示规则图片,根据图片的大小自动调整,不然图片会变得参差不齐。

  参考:https://www.cnblogs.com/android-yus/p/5106462.html

class MyGridView extends GridView {
    private Context context;
    private OnTouchInvalidPositionListener onTouchInvalidPositionListener;
    public MyGridView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    public MyGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    public MyGridView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
    }


    /**
     * ListView嵌套GridView,GridView显示不全问题的解决
     * */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //先创建一个监听接口,一旦点击了无效区域,便实现onTouchInvalidPosition方法,返回true or false来确认是否消费了这个事件
        if(onTouchInvalidPositionListener!=null){
            if(!isEnabled()){
                return isClickable()||isLongClickable();
            }
            int motionPosition = pointToPosition((int)ev.getX(), (int)ev.getY());
            if(ev.getAction()==MotionEvent.ACTION_UP&&motionPosition == INVALID_POSITION){
                super.onTouchEvent(ev);
                return onTouchInvalidPositionListener.onTouchInvalidPosition(motionPosition);
            }
        }
        return super.onTouchEvent(ev);
    }

    public void setOnTouchInvalidPositionListener(
            OnTouchInvalidPositionListener onTouchInvalidPositionListener) {
        this.onTouchInvalidPositionListener = onTouchInvalidPositionListener;
    }


    public interface OnTouchInvalidPositionListener{
        public boolean onTouchInvalidPosition(int motionEvent);
    }

}

Item布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:descendantFocusability="blocksDescendants"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="5dp"
    android:paddingBottom="5dp"
    android:orientation="horizontal">


        <ImageView
            android:id="@+id/image"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_marginLeft="8dp"
            android:src="@drawable/home" />

    <LinearLayout
        android:layout_marginLeft="8dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10sp"
        android:orientation="vertical">

        <TextView
            android:padding="5dp"
            android:id="@+id/name"
            android:text="名字"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />


    <TextView
        android:text="内容"
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <com.example.implanthearts.MyGridView
        android:layout_marginTop="10dp"
        android:id="@+id/gridview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:columnWidth="90dp"
        android:focusable="false"
        android:gravity="center_horizontal"
        android:horizontalSpacing="1dip"
        android:numColumns="3"
        android:stretchMode="columnWidth"
        android:verticalSpacing="12dip"
        >

    </com.example.implanthearts.MyGridView>
        
        <TextView
            android:layout_marginTop="16dp"
            android:layout_marginBottom="12dp"
            android:id="@+id/time"
            android:text="发布时间"
            android:layout_alignParentRight="true"
            android:layout_alignParentBottom="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>

</LinearLayout>
</LinearLayout>

其中一个Item会显示如图:

 

2、获取并显示图片

图片和文字都是从Bmob的Publish表中获取的。获取到的数据都存在list中,list是List<Publish>类型。然后把list传给ListView设配器。

如果不是从Bmob上获取数据,可以直接定义list,然后把数据传给ListView设配器。

    private void loadDate() {
        BmobQuery<Publish> bmobQuery = new BmobQuery<Publish>();
        bmobQuery.findObjects(new FindListener<Publish>() {  //按行查询
            @Override
            public void done(List<Publish> list, BmobException e) {
                if (e == null){
                    //数据倒序显示,最新的数据在最上面
                    Collections.reverse(list);
                    adapter = new ListViewAdapter(getContext(),list);
                    listview.setAdapter(adapter);
                }
            }
        });
    }

ListViewAdapter:

使用ImageLoader加载图片。

ImageLoader使用可看:https://blog.csdn.net/weixin_39492854/article/details/88935088

public  class ListViewAdapter extends BaseAdapter {
    private Context context;
    private List<Publish> list;
    List <String> imageurl;
    GrideViewAdapter adapter;

    private DisplayImageOptions options = new DisplayImageOptions.Builder()
            .showStubImage(R.mipmap.ic_launcher)                      //设置图片下载期间显示的图片
                .showImageForEmptyUri(R.mipmap.ic_launcher)               //设置图片uri为空或者是错位的时候显示的图片
                .showImageOnFail(R.mipmap.ic_launcher)                    //设置图片加载或解码过程中发生错误显示的图片
                .cacheInMemory(true)                                          //设置下载的图片是否缓存在内存中
                .cacheOnDisk(true)                                            //设置下载的图片是否缓存在SD中
                .displayer(new RoundedBitmapDisplayer(20))  // 设置成圆角图片
                .build();                                                     //创建配置或的DisplayImageOption对象

    ImageLoader imageLoader = ImageLoader.getInstance();

    public ListViewAdapter(Context context,List<Publish> list) {
        this.context = context;
        this.list = list;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder;
        if (convertView == null) {
            convertView = View.inflate(context, R.layout.listview_content, null);
            viewHolder = new ViewHolder();
            viewHolder.image = (ImageView) convertView.findViewById(R.id.image);
            viewHolder.name = (TextView) convertView.findViewById(R.id.name);
            viewHolder.text = (TextView) convertView.findViewById(R.id.text);
            viewHolder.time = (TextView)convertView.findViewById(R.id.time);
            viewHolder.gridview = (MyGridView) convertView.findViewById(R.id.gridview);


            convertView.setTag(viewHolder);

        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }


        Publish publish = list.get(position);
        viewHolder.name.setText(publish.getName());//用户名
        viewHolder.text.setText(publish.getMessage());//发表内容
        viewHolder.time.setText("发布时间:"+publish.getTime());//发表时间

        //显示发表消息的用户的头像
        BmobQuery<advertisement> categoryBmobQuery = new BmobQuery<>();
        categoryBmobQuery.addWhereEqualTo("name", publish.getName());//根据用户名查找对应的图片头像
        categoryBmobQuery.findObjects(new FindListener<advertisement>() {
            @Override
            public void done(List<advertisement> object, BmobException e) {
                if (e == null) {
                    String touxiang = object.get(0).getPicture().getFileUrl();
                    Log.w("BMOB",touxiang);

                    imageLoader.displayImage(touxiang, viewHolder.image, options);

                } else {
                    Log.e("BMOB", e.toString());

                }
            }
        });


        if (imageurl == null || imageurl.size() == 0) { // 没有图片资源就隐藏GridView
            viewHolder.gridview.setVisibility(View.GONE);
        } else {
            adapter = new GrideViewAdapter(context,imageurl);
            viewHolder.gridview.setAdapter(adapter);

        }


        return convertView;
    }


    public  class ViewHolder {
        ImageView image;
        TextView name;
        TextView text;
        TextView time;
        MyGridView gridview;
    }
}

GeidViewAdapter:

使用ImageLoader加载图片。

public class GrideViewAdapter extends BaseAdapter{
    private Context context;
    private List<String > picture;
    private DisplayImageOptions options;
    public  GrideViewAdapter (Context context,List<String>picture){
        this.context = context;
        this.picture = picture;
    }

    @Override
    public int getCount() {
        return picture.size();
    }

    @Override
    public Object getItem(int position) {
        return picture.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View view = View.inflate(context, R.layout.item_gridview, null);
        ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);

        options = new DisplayImageOptions.Builder()
                .showStubImage(R.mipmap.ic_launcher)                      //设置图片下载期间显示的图片
                .showImageForEmptyUri(R.mipmap.ic_launcher)               //设置图片uri为空或者是错位的时候显示的图片
                .showImageOnFail(R.mipmap.ic_launcher)                    //设置图片加载或解码过程中发生错误显示的图片
                .cacheInMemory(true)                                          //设置下载的图片是否缓存在内存中
                .cacheOnDisk(true)                                            //设置下载的图片是否缓存在SD中
                .build();                                                     //创建配置或的DisplayImageOption对象

        Log.w("ppp",picture.get(position));
        ImageLoader imageLoader = ImageLoader.getInstance();
        imageLoader.displayImage(picture.get(position), imageView, options);

        return view;
    }

}

这样就可以显示图片了!接下来是点击查看大图,这里重点是要实现ListView和GridView都可以点击,并且要记录是点击了哪个ListView的Item的图片。

ListView的Item在滑动的时候,会重新获取刚刚因为滑动被隐藏(在屏幕外)的图片,如果不记录位置的话,会导致点击图片查看大图的时候,显示的并不是我们想要的那个图片,会产生错位。

参考:https://www.cnblogs.com/android-yus/p/5098206.html

1、记录位置

在ListViewAdapter中添加:

//给当前的GridView设置一个位置标记
viewHolder.gridview.setTag(position);

 在GridView的点击事件中添加:

//GridView在ListView条目里的位置
int lv_item_position= (Integer) parent.getTag();

2、GridView查看大图

 这里我采用的是在最开始获取list的时候,就记录好每个item有几张图,存进a二维数组里面,代表总共有多少条消息,每条消息有多少张图片。a二维数组为static变量。

                    //总共有多少条朋友圈
                    size = list.size();
                    Log.w("nnn","总共有多少条朋友圈="+size);
                    a=new String [size][];
                     n  = new int[size];

                    //每条朋友圈的图片数量
                    for(int i = 0;i<size;i++){
                        Log.w("nnn","每条朋友圈的图片数量="+list.get(i).getN());
                        n[i] = list.get(i).getN();
                        a[i] = new String[list.get(i).getN()];
                        for(int j =0;j<list.get(i).getN();j++){
                            a[i][j] = list.get(i).getPicture().get(j).getFileUrl();
                            Log.w("nnn","图片地址"+a[i][j]);
                        }
                    }

 在后面查看大图的时候根据item的位置,查找a二维数组,存进b变量以便显示图片。

            //获取点击的图片,查看对应消息的所有大图
           List<String> b = new ArrayList<>();

            for(int i = 0;i<CommunityFragment.size;i++){
                if(i==lv_item_position){
                    for(int j = 0;j <CommunityFragment.n[i];j++){
                         b.add( CommunityFragment.a[i][j]);
                    }

                }
            }

3、点击任意图片可滑动查看大图

把b传进ShowImageActivity查看大图。使用ViewPager显示图片。

使用Parcelable传递位置和图片。

public class Image implements Parcelable {
    private int id;
    private List<String> imageurl;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public List<String> getImageurl() {
        return imageurl;
    }

    public void setImageurl(List<String> imageurl) {
        this.imageurl = imageurl;
    }


    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeStringList(imageurl);
    }

    public static final Parcelable.Creator<Image> CREATOR = new Parcelable.
            Creator<Image>() {


        @Override
        public Image createFromParcel(Parcel source) {
            Image image = new Image();
            image.id = source.readInt();
            if (image.imageurl == null) {
                image.imageurl = new ArrayList<String>();
            }
            source.readStringList(image.imageurl);
            return image;
        }

        @Override
        public Image[] newArray(int size) {
            return new Image[size];
        }
    };

}
Image image = new Image();
image.setId(position);
image.setImageurl(b);

Intent intent = new Intent(context,ShowImageActivity.class);
intent.putExtra("data",image);

获取位置和图片:

        Image image  = (Image)getIntent().getParcelableExtra("data");
        int id = image.getId();
        List<String> imageurl = image.getImageurl();

将图片添加到ViewPager中:

        for (int i = 0; i < imageurl.size() ; i++) {  //for循环将试图添加到list中
            View view = LayoutInflater.from(getApplicationContext()).inflate(
                    R.layout.view_pager_item, null);   //绑定viewpager的item布局文件
            ImageView iv = (ImageView) view.findViewById(R.id.view_image);   //绑定布局中的id

//            Log.w("BBB",image.getId(i));
            options = new DisplayImageOptions.Builder()
                    .showStubImage(R.mipmap.ic_launcher)                      //设置图片下载期间显示的图片
                    .showImageForEmptyUri(R.mipmap.ic_launcher)               //设置图片uri为空或者是错位的时候显示的图片
                    .showImageOnFail(R.mipmap.ic_launcher)                    //设置图片加载或解码过程中发生错误显示的图片
                    .cacheInMemory(true)                                          //设置下载的图片是否缓存在内存中
                    .cacheOnDisk(true)                                            //设置下载的图片是否缓存在SD中
                    .build();                                                     //创建配置或的DisplayImageOption对象

            //设置当前点击的图片
            ImageLoader imageLoader = ImageLoader.getInstance();
            imageLoader.displayImage(imageurl.get(i), iv, options);


            listViews.add(view);
            /**
             * 图片的长按监听
             * */
            iv.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    //弹出提示,提示内容为当前的图片位置
                    Toast.makeText(ShowImageActivity.this, "这是第" + (index + 1) + "图片", Toast.LENGTH_SHORT).show();
                    return false;
                }
            });
        }

ViewPager的item布局采用PhotoView,实现双击、手势放大图片。

<com.github.chrisbanes.photoview.PhotoView
    android:layout_centerInParent="true"
    android:id="@+id/view_image"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

使用PhotoView需要以下步骤:

1、app的build.gradle中添加:

implementation 'com.github.chrisbanes:PhotoView:2.0.0'

2、在项目的build.gradle中的allprojects添加:

        maven {
            url "https://jitpack.io"
        }

至此就完成啦!

源码等整理后放GitHub。

评论 8 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

weixin_39492854

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值