Android 制作依赖库 供其他项目依赖使用教程一 , 制作一个自定义PopupWindow弹窗,仿微信右上角添加菜单弹窗

  • 前言
  • 零、弹窗效果图
  • 一、查找和制作素材
  • 二、新建一个项目添加一个Module
  • 三、Module开发之写布局
  • 四、Module开发之写实体类
  • 五、Module开发之写Adapter
  • 六、Module开发之写DLPopupWindow
  • 七、使用
  • Github


前言

在Android开发项目的时候,我们经常会去找有没有现成的“轮子”,也就是依赖库,别人做好的控件或者架构库。我们直接在build.gradle里添加一行 implementation 'com.android.support:appcompat-v7:28.0.0'之类的就能引用别人的文件了。

但是,如果我们有做好的“轮子”,想共享出去给别人使用呢,应该怎么做?
这个内容将分为两部分:

一、制作一个自定义PopupWindow弹窗库,仿照微信的右上角添加菜单弹窗
二、上传制作的库到GitHub,生成release版本,共享出来

Android 制作依赖库 供其他项目依赖使用教程(二) 添加到GitHub 共享到公共库JitPack

这篇文章将讲述第一部分

零、弹窗效果图

这里做了两种样式

一种是仿微信的

另一种是自定义的默认模式

android创建viewgroup底部菜单_自定义控件


android创建viewgroup底部菜单_自定义控件_02

android创建viewgroup底部菜单_自定义控件_03

一、查找和制作素材

弹窗上面有几个东西用代码画出来是比较困难的,第一个是背景,也就是那个框;第二个就是文字左侧的图标,像下面这个扫一扫的图标。先来说这种特别的图标,这种图其实可以在 阿里巴巴矢量图标库 里找到,基本都会有的。

android创建viewgroup底部菜单_自定义控件_04


第一个背景框的话就比较麻烦了,如果是简单的长方形之类的,想要比较漂亮的阴影,可以选择去这个网站 Android 9-patch shadow generator 他这里能直接建立.9图,特别的方便,下次单独写一篇小博客介绍下,到时候再更新这个位置。

如果像是微信这种不太规则的背景框,我们可以使用PhotoShop来做,或者直接叫UI给切图,然后做成.9图来使用。

这一部分内容等另一篇文章来详细介绍。

我的相关博客:
Android 制作.9.png图片之利用Android 9-patch shadow generatorAndroid 制作.9.png图片之利用Android studio

二、新建一个项目添加一个Module

新建项目就不多说啦,能查询到这篇文章的都不是没用过Android studio的人了。

我们就直接在一个新建的项目里添加一个新的库

android创建viewgroup底部菜单_android_05


选择Android Library,点击Next,填写好名称后完成。

然后在settings.gradle文件中添加库名称 ‘:dlpopwindow’

include ':app', ':dlpopwindow'

接着在app文件夹里的build.gradle文件中的 dependencies 里添加

implementation project(':dlpopwindow')

这样子,app就能引用到了 dlpopwindow

三、Module开发之写布局

布局文件有两个
一个是popupwindow的布局;
另一个是弹窗的选项的布局;

布局一、pop_window.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_bg"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/menu_open"
    android:orientation="vertical">

    <ListView
        android:id="@+id/listview"
        android:layout_width="135dp"
        android:layout_height="wrap_content"
        android:divider="@null" />
</LinearLayout>

布局二、pop_item.xml

<?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"
    android:layout_width="135dp"
    android:layout_height="45dp"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/img_icon"
            android:layout_width="20dp"
            android:layout_height="match_parent"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="10dp"
            android:src="@drawable/scan"
            android:visibility="visible" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/txt"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center_vertical"
                android:text="添加设备"
                android:textColor="@android:color/tertiary_text_light"
                android:textSize="16sp" />

            <ImageView
                android:id="@+id/img_line"
                android:layout_width="match_parent"
                android:layout_height="1px"
                android:layout_alignParentBottom="true"
                android:background="#888888" />
        </LinearLayout>

    </LinearLayout>

</LinearLayout>

四、Module开发之写实体类

我们会需要一个实体类来存储,自定义的弹窗列表的数据

/**
 * 选项的属性
 * @author  dlong
 * created at 2019/3/15 9:44 AM
 */
public class DLPopItem {
    /** 图标 */
    private int icon = 0;
    /** 文字 */
    private String text;
    /** 文字、图标 颜色 */
    private int color = 0x888888;

    public DLPopItem(){

    }

    public DLPopItem(int i, String t, int c){
        icon = i;
        text = t;
        color = c;
    }

    public int getIcon() {
        return icon;
    }

    public String getText() {
        return text;
    }

    public void setIcon(int icon) {
        this.icon = icon;
    }

    public void setText(String text) {
        this.text = text;
    }

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }
}

五、Module开发之写Adapter

我们会需要一个Adapter来给listview绘制子项的方法

/**
 * 列表适配器
 * @author  dlong
 * created at 2019/3/14 1:45 PM
 */
public class PopAdapter extends BaseAdapter {
    private Context mContext;
    private List<DLPopItem> mList;
    private DLPopItem mItem;

    public PopAdapter(Context context, List<DLPopItem> list){
        mContext = context;
        mList = list;
    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder mHolder;
        if (convertView == null) {
            mHolder = new ViewHolder();
            convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.pop_item, parent, false);
            mHolder.imgIcon = (ImageView) convertView.findViewById(R.id.img_icon);
            mHolder.imgLine = (ImageView) convertView.findViewById(R.id.img_line);
            mHolder.txt = (TextView) convertView.findViewById(R.id.txt);

            convertView.setTag(mHolder);
        } else {
            mHolder = (ViewHolder) convertView.getTag();
        }
        mItem = mList.get(position);
        // 设置图标
        mHolder.imgIcon.setImageResource(mItem.getIcon());
        // 设置文本
        mHolder.txt.setText(mItem.getText());
        // 设置图标颜色
        int cd = mItem.getColor();
        if (cd < 0x01000000){
            cd = 0xff000000 + cd;
        }
        mHolder.imgIcon.setColorFilter(cd);
        // 设置下拉线颜色
        int cc = cd & 0x33ffffff;
        mHolder.imgLine.setBackgroundColor(cc);
        // 设置文本颜色
        mHolder.txt.setTextColor(cd);
        // 如果是最后一项就不显示下划线
        if (position == mList.size()-1){
            mHolder.imgLine.setVisibility(View.GONE);
        }else {
            mHolder.imgLine.setVisibility(View.VISIBLE);
        }
        // 如果没有图标文字就居中显示
        if (mItem.getIcon() == 0){
            mHolder.txt.setGravity(Gravity.CENTER);
            mHolder.imgIcon.setVisibility(View.GONE);
        }else {
            mHolder.txt.setGravity(Gravity.CENTER_VERTICAL);
            mHolder.imgIcon.setVisibility(View.VISIBLE);
        }
        return convertView;
    }

    private class ViewHolder{
        ImageView imgIcon, imgLine;
        TextView txt;
    }
}

六、Module开发之写DLPopupWindow

最后写继承了PopupWindow的自定义DLPopupWindow

/**
 * 右上角菜单弹窗
 * @author  dlong
 * created at 2019/3/14 11:05 AM
 */
public class DLPopupWindow extends PopupWindow{

    /**
     * 定义一个接口
     */
    public interface OnItemClickListener{
        void OnClick(int position);
    }

    /** 实例化 */
    private OnItemClickListener onItemClickListener = null;

    /**
     * 设置点击回调
     * @param on
     */
    public void setOnItemClickListener(OnItemClickListener on){
        this.onItemClickListener = on;
    }

    /** 微信样式 */
    public static final int STYLE_WEIXIN = 1;
    /** 默认样式 */
    public static final int STYLE_DEF = 2;

    /** 上下文 */
    private Context mContext;
    private LayoutInflater mInflater;
    private View mContentView;
    /** 适配器 */
    private PopAdapter mAdapter;
    /** 数据列表 */
    private List<DLPopItem> mList;

    public DLPopupWindow(Context context, List<DLPopItem> list, int style){
        this.mContext = context;
        this.mList = list;

        // 打气筒
        mInflater = LayoutInflater.from(mContext);
        // 打气
        mContentView = mInflater.inflate(R.layout.pop_window,null, false);
        // 设置View
        setContentView(mContentView);
        // 设置宽与高
        setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
        setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
        // 设置可以获取集点
        setFocusable(true);
        // 设置背景只有设置了这个才可以点击外边和BACK消失
        setBackgroundDrawable(new ColorDrawable());
        // 设置点击外边可以消失
        setOutsideTouchable(true);

        // 获得listview
        ListView listView = (ListView) mContentView.findViewById(R.id.listview);
        mAdapter = new PopAdapter(mContext, mList);
        listView.setAdapter(mAdapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // 回调
                onItemClickListener.OnClick(position);
                dismiss();
            }
        });
        LinearLayout llBG = (LinearLayout) mContentView.findViewById(R.id.ll_bg);
        // 根据类型修改背景
        switch (style){
            case STYLE_WEIXIN:
                llBG.setBackgroundResource(R.drawable.menu_open_weixin);
                break;
            default:
                llBG.setBackgroundResource(R.drawable.menu_open);
                break;
        }
    }
}

Module开发就这样完成了

七、使用

public class MainActivity extends AppCompatActivity {

    /** 上下文 */
    private Context mContext = this;
    /** 自定义弹窗实例化 */
    private DLPopupWindow popupWindow;
    /** 数据列表 */
    private List<DLPopItem> mList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DLPopItem item = new DLPopItem(R.mipmap.message, "发起群聊", 0xffffff);
        mList.add(item);
        item = new DLPopItem(R.mipmap.add_friend, "添加朋友", 0xffffff);
        mList.add(item);
        item = new DLPopItem(R.mipmap.scaning, "扫一扫", 0xffffff);
        mList.add(item);
        item = new DLPopItem(R.mipmap.pay, "收付款", 0xffffff);
        mList.add(item);
        popupWindow = new DLPopupWindow(mContext, mList, DLPopupWindow.STYLE_WEIXIN);

        /*DLPopItem item = new DLPopItem(0, "添加设备", 0x888888);
        mList.add(item);
        item = new DLPopItem(0, "扫一扫", 0x888888);
        mList.add(item);
        popupWindow = new DLPopupWindow(mContext, mList, DLPopupWindow.STYLE_DEF);*/

        popupWindow.setOnItemClickListener(new DLPopupWindow.OnItemClickListener() {
            @Override
            public void OnClick(int position) {
                Toast.makeText(mContext, mList.get(position).getText(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     * 加号点击事件
     * @param view
     */
    public void OpenPop(View view){
        popupWindow.showAsDropDown(view, 0, 0);
    }
}

就此“轮子”已经做成, 系列二 将会介绍怎么将“轮子”添加到 公共库 ,供所有人使用。
Android 制作依赖库 供其他项目依赖使用教程(二) 添加到GitHub 共享到公共库JitPack

Github

这个项目的GitHub地址 DLPopWindowTest 使用方法如下

// 添加到项目根目录的build.gradle文件中
allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}
// 添加依赖
	dependencies {
	        implementation 'com.github.D10NGYANG:DLPopWindowTest:1.0.0'
	}