欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android仿微信朋友圈图片上传选择器布局

程序员文章站 2022-05-12 22:53:41
...

标题有点绕口,直接上一个效果图,如果符合你的需求的请在往下看,避免浪费你的时间
Android仿微信朋友圈图片上传选择器布局
当当当当,标红的区域就是今天我们要干的活了 ,搞起来!

思路:

对android有点了解的人都知道在列表显示中我们可以使用GridLayoutManager这个布局可以轻松实现图片文字的一行显示的个数,所以在使用recyclerview渲染列表的时候我们就使用GridLayoutManager这个布局来代替以往的LinearLayoutManager
然后在适配器方面我们直接写一个类继承RecyclerView.Adapter来手把手实现我们想要的功能,其中我们在重写**getItemCount()**这个方法是 因为我们要在显示的图片列表的最后加上一个添加的图片 ,所以我们的这个方法返回的个数应该是我们当前数据的个数加1 这里也算是本章博客的一个小重点了,关于我们图片上传选择器布局的实现主要还是围绕这里进行扩展的。
Android仿微信朋友圈图片上传选择器布局
好了,废话不多说,直接开始欢乐的代码时间!

主活动中的布局:

Android仿微信朋友圈图片上传选择器布局
代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".activity.ContainSendActivity">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp">
        <ImageView
            android:layout_margin="5dp"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/icon_back"/>
        <Button
            android:textColor="#ffffff"
            android:layout_margin="@dimen/dp_10"
            android:background="#009933"
            android:layout_alignParentRight="true"
            android:text="发表"
            android:clickable="false"
            android:layout_width="wrap_content"
            android:layout_height="50dp"/>
    </RelativeLayout>

    <EditText
        android:gravity="start"
        android:layout_margin="10dp"
        android:hint="记录点滴幸福。。。。"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
         android:background="@null"
         android:lines="6"
        />
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/send_recycler"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

</LinearLayout>

两个recyclerview要显示的布局文件

这里就不贴效果图片了 很简单就是两个图片 显示的内容不同罢了
send_item_final.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/defaultimg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        app:srcCompat="@drawable/icon_add"
        android:contentDescription="TODO" />
</androidx.cardview.widget.CardView>

send_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="4dp"
    android:orientation="vertical">


    <ImageView
        android:id="@+id/imageView6"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop"
        android:src="@drawable/smart"
        />
</androidx.cardview.widget.CardView>

适配器代码

public class SendBlogAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
    private Context context;
    private List<String> data;

    private static final int ITEM_ONE=1;
    private static final int ITEM_TWO=2;
    public SendBlogAdapter(Context context,List<String> data){
        this.context = context;
        this.data = data;

    }

  
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view;
        RecyclerView.ViewHolder holder;
        if(viewType==ITEM_TWO){
             view = LayoutInflater.from(parent.getContext()).inflate(R.layout.send_ittem_final,parent,false);
             holder = new AnoViewHolder(view);
        }else {
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.send_item,parent,false);
            holder = new ViewHolder(view);
        }
        return holder;

    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof AnoViewHolder) {
            ((AnoViewHolder) holder).img.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context,"im specatil",Toast.LENGTH_SHORT).show();
                }
            });
        }else {
            ((ViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context,"im nomal",Toast.LENGTH_SHORT).show();
                }
            });
        }

    }


    @Override
    public int getItemCount() {
        return data.size()+1;
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        private ImageView imageView;
        public ViewHolder(View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.imageView6);
            
        }
    }

    public class AnoViewHolder extends RecyclerView.ViewHolder{
        private ImageView img;

        public AnoViewHolder(@NonNull View itemView) {
            super(itemView);
            img = itemView.findViewById(R.id.defaultimg);
            img.setOnClickListener(this);
        }
    }

    @Override
    public int getItemViewType(int position) {
        if(position>data.size()-1){
            return ITEM_TWO;
        }else {
            return ITEM_ONE;
        }
    }
}

详解以及自己遇到的BUG分享

首先说明上面的适配器代码是修改好的 复制到你的程序中完全是可用的 ,只是将自己在实现这个功能时遇到的异常和大家做一个分享,避免你以后在遇到同样问题时不知道该如何去处理,也算是一个小的总结。

思路:

我们要在传过来的数据中进行判断,当当前显示的时最后一个传过来的数据时,我们在他的后面显示我们之前放好的添加图片的那个布局图片,所以我声明了2个变量在我们的**getItemViewType()方法中进行判断,如果当前的position大于我们穿过来的数据,就说明当前位置我们应该显示添加图片的那个布局了,然后我们在onCreateViewHolder()**中根据viewType参数进行比对,将我们要显示的添加图片显示上来 到这一步 我们的程序是可以实现静态布局的 注意这里说的是只是实现静态布局。

我遇到的BUG详解

我们在使用微信发朋友圈时 他是会根据我们点击选中的时图片还是添加进行判断,如果是选择的图片他会进入一个图片详情界面,如果是添加图片时他会执行另外一个逻辑,我第一次的思路是直接在一个ViewHolder中实例化我们两个布局中的ImageView ,在onBindViewHolder中看看代码会不会自动根据我们选中的图片进行逻辑处理,结果程序直接崩溃了,然后就写了两个viewHolder 都直接继承RecyclerView.ViewHolder,这样在onCreateViewHolder()中判断当前改初始化那个布局了,将结果返回给我们定义的ViewHolder中,然后在onBindViewHolder()中我们就可以根据holder找到他的孩子了 就可以进行两个布局中各事件的处理了

扩展

在adapter中处理我们的事件操作就不是很方便,我还想在选择图片时加一个底部弹出框,就想着把点击事件在我们要显示的布局中进行处理,就仿照点击事件接口将点击事件的触发写在了activity中
扩展后的adapter:

public class SendBlogAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
    private Context context;
    private List<String> data;

    private static final int ITEM_ONE=1;
    private static final int ITEM_TWO=2;
    public SendBlogAdapter(Context context,List<String> data){
        this.context = context;
        this.data = data;

    }

    private OnItemClickListener clickListener;

    public void setClickListener(OnItemClickListener clickListener) {
        this.clickListener = clickListener;
    }

    public interface OnItemClickListener {
        void onClick(View view, int position);
        void onSelected(View view,int position);
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view;
        RecyclerView.ViewHolder holder;
        if(viewType==ITEM_TWO){
             view = LayoutInflater.from(parent.getContext()).inflate(R.layout.send_ittem_final,parent,false);
             holder = new AnoViewHolder(view);
        }else {
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.send_item,parent,false);
            holder = new ViewHolder(view);
        }
        return holder;

    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
//        if (holder instanceof AnoViewHolder) {
//            ((AnoViewHolder) holder).img.setOnClickListener(new View.OnClickListener() {
//                @Override
//                public void onClick(View v) {
//                    Toast.makeText(context,"im specatil",Toast.LENGTH_SHORT).show();
//                }
//            });
//        }else {
//            ((ViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() {
//                @Override
//                public void onClick(View v) {
//                    Toast.makeText(context,"im nomal",Toast.LENGTH_SHORT).show();
//                }
//            });
//        }

    }


    @Override
    public int getItemCount() {
        return data.size()+1;
    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
        private ImageView imageView;
        public ViewHolder(View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.imageView6);
            imageView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            if(clickListener!=null){
                clickListener.onSelected(itemView, getAdapterPosition());
            }
        }
    }

    public class AnoViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
        private ImageView img;

        public AnoViewHolder(@NonNull View itemView) {
            super(itemView);
            img = itemView.findViewById(R.id.defaultimg);
            img.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            if(clickListener!=null){
                clickListener.onClick(itemView, getAdapterPosition());
            }
        }
    }

    @Override
    public int getItemViewType(int position) {
        if(position>data.size()-1){
            return ITEM_TWO;
        }else {
            return ITEM_ONE;
        }
    }
}

最后就是在我们activity中的引用了:(这里使用的是kotlin)

       fun initData() {

        var array4 = arrayOf("1","2","3")
        send_recycler.layoutManager  = GridLayoutManager(this,3)
        var adapter = SendBlogAdapter(this, array4.toMutableList())
        send_recycler.adapter = adapter
        adapter.setClickListener(object :SendBlogAdapter.OnItemClickListener{
            override fun onSelected(view: View?, position: Int) {//添加图片点击的事件监听
                Toast.makeText(this@ContainSendActivity,"======",Toast.LENGTH_SHORT).show()
            }

            override fun onClick(view: View?, position: Int) {//选中已添加的图片点击的事件监听
                Toast.makeText(this@ContainSendActivity,"didia",Toast.LENGTH_SHORT).show()
            }

        })
    }

最后上一个我做好的效果图:
Android仿微信朋友圈图片上传选择器布局
界面有点丑哈 在后面我会进行优化的 嘻嘻
欧克,到这里我们的仿微信朋友圈图片上传选择器布局的实现就算完成了。
在后面的章节中我也会将微信朋友圈的功能一点点的做出来的并且记录下来,动态添加删除图片,图片的选择方式,图片浏览的功能等等 ,,,
编写不易,请大家多多点赞支持 !!!!
Android仿微信朋友圈图片上传选择器布局