美文网首页编程AppAndroid开发实战总结
Android自定义菜单选择条目

Android自定义菜单选择条目

作者: 键盘上的麒麟臂 | 来源:发表于2017-10-16 19:37 被阅读350次

一.需求

有时候我们需要在项目里做一个菜单样式的功能,比如美团的

image.png

再比如JD的

image.png

有时候很多个app需要这样的UI,或者一个app里面有多个地方需要,那如果重复写的话就会很麻烦,我们可以自定义一个View,然后在多处复用。我知道你恨牛逼搭这个页面只要一两分钟,但是即使再快,重复去做相同的事情也是不聪明的选择。

二.自定义View实现菜单选择条目

首先确定我们需要做出一个什么样的效果。看了很多地方,我觉得可以做成这样子的

image.png

左右两个textview,两个imageview,但是我觉得有些可能需要显示在中间,所以我做了3个textview。全显示的话大概会是这个样子

image.png

特定的需求可以隐藏特定地方的控件。

代码:

1.xml文件
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/rl_content"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:id="@+id/tv_title_center"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:text="cccc"
        />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/iv_left"
        android:layout_centerVertical="true"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/iv_left"
        android:layout_toLeftOf="@+id/tv_title_center"
        android:text="aaaa"
        android:layout_centerVertical="true"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:id="@+id/tv_title_left"
        android:maxLines="1"
        android:ellipsize="end"
        />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:id="@+id/iv_right"
        />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingTop="15dp"
        android:paddingBottom="15dp"
        android:text="bbb"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/tv_title_center"
        android:layout_toLeftOf="@+id/iv_right"
        android:id="@+id/tv_title_right"
        android:gravity="right"
        android:maxLines="1"
        android:ellipsize="end"
        />

</RelativeLayout>
2.attrs
<!-- 菜单选择栏 -->
    <declare-styleable name="menu_options_view_style">
        <attr name="title_left" format="string"/>
        <attr name="title_right" format="string"/>
        <attr name="title_center" format="string"/>
        <attr name="img_left_src" format="reference"/>
        <attr name="img_right_src" format="reference"/>
        
        <attr name="imgLpadding" format="dimension"/>
        <attr name="imgRpadding" format="dimension"/>
        
        <attr name="imgLmargin" format="dimension"/>
        <attr name="imgRmargin" format="dimension"/>

        <attr name="leftTvSize" format="dimension"/>
        <attr name="rightTvSize" format="dimension"/>
        <attr name="centerTvSize" format="dimension"/>
        
    </declare-styleable>
3.自定义View
public class MenuOptionsView extends FrameLayout implements View.OnClickListener{

    private RelativeLayout rlContent;
    private ImageView leftImg;
    private ImageView rightImg;
    private TextView leftText;
    private TextView rightText;
    private TextView centerText;
    private View contentView;

    private Context context;
    private String leftTitle = null;
    private String rightTitle = null;
    private String centerTitle = null;
    private int leftImgIds;
    private int rightImgIds;
    private float imgLpadding;
    private float imgRpadding;
    private float imgLmargin;
    private float imgRmargin;
    private float leftTvSize;
    private float rightTvSize;
    private float centerTvSize;

    private MenuOptionsLImgClickListener menuOptionsLImgClickListener;
    private MenuOptionsRImgClickListener menuOptionsRImgClickListener;
    private MenuOptionsLTvClickListener menuOptionsLTvClickListener;
    private MenuOptionsRTvClickListener menuOptionsRTvClickListener;
    private MenuOptionsCTvClickListener menuOptionsCTvClickListener;
    private MenuOptionsClickListener menuOptionsClickListener;

    public MenuOptionsView(Context context) {
        super(context);
        this.context = context;
    }

    public MenuOptionsView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init(context, attrs);
    }

    public MenuOptionsView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init(context, attrs);
    }

    private void init(Context context,AttributeSet attrs)  {
        TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.menu_options_view_style);
        leftTitle = typedArray.getString(R.styleable.menu_options_view_style_title_left);
        rightTitle = typedArray.getString(R.styleable.menu_options_view_style_title_right);
        centerTitle = typedArray.getString(R.styleable.menu_options_view_style_title_center);
        leftImgIds = typedArray.getResourceId(R.styleable.menu_options_view_style_img_left_src,-1);
        rightImgIds = typedArray.getResourceId(R.styleable.menu_options_view_style_img_right_src,-1);

        imgLpadding = typedArray.getDimension(R.styleable.menu_options_view_style_imgLpadding,0);
        imgRpadding = typedArray.getDimension(R.styleable.menu_options_view_style_imgRpadding,0);
        imgLmargin = typedArray.getDimension(R.styleable.menu_options_view_style_imgLmargin,0);
        imgRmargin = typedArray.getDimension(R.styleable.menu_options_view_style_imgRmargin,0);

        leftTvSize = typedArray.getDimension(R.styleable.menu_options_view_style_leftTvSize,0);
        rightTvSize = typedArray.getDimension(R.styleable.menu_options_view_style_rightTvSize,0);
        centerTvSize = typedArray.getDimension(R.styleable.menu_options_view_style_centerTvSize,0);
        typedArray.recycle();
        initView();
    }

    private void initView(){
        contentView = LayoutInflater.from(context).inflate(R.layout.layout_menu_options,null);
        this.addView(contentView);

        leftImg = (ImageView) contentView.findViewById(R.id.iv_left);
        rightImg = (ImageView) contentView.findViewById(R.id.iv_right);
        leftText = (TextView) contentView.findViewById(R.id.tv_title_left);
        rightText = (TextView) contentView.findViewById(R.id.tv_title_right);
        centerText = (TextView) contentView.findViewById(R.id.tv_title_center);
        rlContent = (RelativeLayout) contentView.findViewById(R.id.rl_content);

        tvStatChange();

        leftImg.setImageResource(leftImgIds);
        rightImg.setImageResource(rightImgIds);
        leftText.setText(leftTitle);
        rightText.setText(rightTitle);
        centerText.setText(centerTitle);

        leftText.setTextSize(TypedValue.COMPLEX_UNIT_PX,leftTvSize+1);
        rightText.setTextSize(TypedValue.COMPLEX_UNIT_PX,rightTvSize+1);
        centerText.setTextSize(TypedValue.COMPLEX_UNIT_PX,centerTvSize+1);

        leftImg.setPadding((int)imgLpadding,(int)imgLpadding,(int)imgLmargin,(int)imgLpadding);
        rightImg.setPadding((int)imgRmargin,(int)imgRpadding,(int)imgRpadding,(int)imgRpadding);

        leftImg.setOnClickListener(this);
        rightImg.setOnClickListener(this);
        leftText.setOnClickListener(this);
        rightText.setOnClickListener(this);
        centerText.setOnClickListener(this);
        rlContent.setOnClickListener(this);
    }

    private int dp2px(float dpValue){
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.iv_left:
                if (menuOptionsClickListener != null){
                    menuOptionsClickListener.layoutClick();
                    break;
                }
                if (menuOptionsLImgClickListener != null){
                    menuOptionsLImgClickListener.leftImgClick();
                }
                break;
            case R.id.iv_right:
                if (menuOptionsClickListener != null){
                    menuOptionsClickListener.layoutClick();
                    break;
                }
                if (menuOptionsRImgClickListener != null){
                    menuOptionsRImgClickListener.rightImgClick();
                }
                break;
            case R.id.tv_title_left:
                if (menuOptionsClickListener != null){
                    menuOptionsClickListener.layoutClick();
                    break;
                }
                if (menuOptionsLTvClickListener != null){
                    menuOptionsLTvClickListener.leftTvClick();
                }
                break;
            case R.id.tv_title_right:
                if (menuOptionsClickListener != null){
                    menuOptionsClickListener.layoutClick();
                    break;
                }
                if (menuOptionsRTvClickListener != null){
                    menuOptionsRTvClickListener.rightTvClick();
                }
                break;
            case R.id.tv_title_center:
                if (menuOptionsClickListener != null){
                    menuOptionsClickListener.layoutClick();
                    break;
                }
                if (menuOptionsCTvClickListener != null){
                    menuOptionsCTvClickListener.centerClick();
                }
                break;
            case R.id.rl_content:
                if (menuOptionsClickListener != null){
                    menuOptionsClickListener.layoutClick();
                }
                break;
        }
    }

    public int sp2px(float spVal)
    {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                spVal, context.getResources().getDisplayMetrics());
    }

    /**
     *  动态设置3个TextView的显示和隐藏
     */
    public void tvStatChange(){
        int k = 0;
        centerText.setVisibility(GONE);

        if ((centerTitle == null)||(centerTitle.equals(""))){
            centerText.setVisibility(GONE);
        }else {
            // 显示中间的内容时候,左右就隐藏
            centerText.setVisibility(VISIBLE);
            leftText.setVisibility(GONE);
            rightText.setVisibility(GONE);
            return;
        }

        if ((leftTitle == null)||(leftTitle.equals(""))){
            leftText.setVisibility(GONE);
        }else {
            leftText.setVisibility(VISIBLE);
            k++;
        }

        if ((rightTitle == null)||(rightTitle.equals(""))){
            rightText.setVisibility(GONE);
        }else {
            rightText.setVisibility(VISIBLE);
            k++;
        }
        // 如果显示两边的情况下,让中间分割
        if (k == 2){
            centerText.setVisibility(VISIBLE);
        }

    }

    public void setLeftText(String str){
        leftTitle = str;
        leftText.setText(leftTitle);
        tvStatChange();
    }

    public void setRightText(String str){
        rightTitle = str;
        rightText.setText(rightTitle);
        tvStatChange();
    }

    public void setCenterText(String str){
        centerTitle = str;
        centerText.setText(centerTitle);
        tvStatChange();
    }

    public String getLeftTitle() {
        return leftTitle;
    }

    public String getRightTitle() {
        return rightTitle;
    }

    public String getCenterTitle() {
        return centerTitle;
    }

    public void setLeftImgSrc(int Ids){
        leftImg.setImageResource(Ids);
    }

    public void setRightImgSrc(int Ids){
        rightImg.setImageResource(Ids);
    }

    public interface MenuOptionsLImgClickListener{
        void leftImgClick();
    }

    public interface MenuOptionsRImgClickListener{
        void rightImgClick();
    }

    public interface MenuOptionsLTvClickListener{
        void leftTvClick();
    }

    public interface MenuOptionsRTvClickListener{
        void rightTvClick();
    }

    public interface MenuOptionsCTvClickListener{
        void centerClick();
    }

    public interface MenuOptionsClickListener{
        void layoutClick();
    }

    public void setMenuOptionsLImgClickListener(MenuOptionsLImgClickListener menuOptionsLImgClickListener) {
        this.menuOptionsLImgClickListener = menuOptionsLImgClickListener;
    }

    public void setMenuOptionsRImgClickListener(MenuOptionsRImgClickListener menuOptionsRImgClickListener) {
        this.menuOptionsRImgClickListener = menuOptionsRImgClickListener;
    }

    public void setMenuOptionsLTvClickListener(MenuOptionsLTvClickListener menuOptionsLTvClickListener) {
        this.menuOptionsLTvClickListener = menuOptionsLTvClickListener;
    }

    public void setMenuOptionsRTvClickListener(MenuOptionsRTvClickListener menuOptionsRTvClickListener) {
        this.menuOptionsRTvClickListener = menuOptionsRTvClickListener;
    }

    public void setMenuOptionsCTvClickListener(MenuOptionsCTvClickListener menuOptionsCTvClickListener) {
        this.menuOptionsCTvClickListener = menuOptionsCTvClickListener;
    }

    public void setMenuOptionsClickListener(MenuOptionsClickListener menuOptionsClickListener) {
        this.menuOptionsClickListener = menuOptionsClickListener;
    }
}

代码虽然有些长,但是挺简单的。我这里没有写完设置所有的属性,因为有点多,我只写了一些我暂时用到的,其它的常用属性在需要用到的时候我再加上去,比如说字体的颜色之类的。

这段代码有几个地方注意一下就行。
(1)设置字体大小的时候用.setTextSize(TypedValue.COMPLEX_UNIT_PX,leftTvSize+1); 这样才能对应在xml中设置sp的正确尺寸。
(2)我这定义了6个接口来写点击事件,分别是两个imageview和3个textview和父布局的点击事件。我这做操作,如果设置父布局的点击监听,那就会无效所有子控件的点击。
(3)tvStatChange()这个方法是用来做3个textview的动态布局操作,防止他们在某个时刻展示冲突。

4.调用

<com.xxxxx.xxxxx.components.widget.view.MenuOptionsView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:img_left_src = "@mipmap/setting_security"
app:img_right_src = "@mipmap/icon_arrow_right"
app:title_left = "aaaaaa"
app:imgLpadding = "15dp"
app:imgRpadding = "8dp"
app:imgLmargin = "15dp"
app:leftTvSize = "16sp"
android:id="@+id/test"
android:background="@color/white"
>
</com.xxxxx.xxxxx.components.widget.view.MenuOptionsView>

可以看出调用非常简单,唯一的缺点是 app:这个标签无法联想,所以有时候属性多了要进attrs里面去查属性。

三.总结

写这个东西也不难,唯一的不足是子view的属性多,但是可以在用到的时候再去添加特定的属性。
写这个的目的是为了说明有时候我们很犹豫一个东西要不要封装起来,就像这个一个,写个imageview和textview有必要封装吗?我复制粘贴就能实现了。我个人比较建议封装,再小的轮子也是轮子,而且这些东西封装起来也不难,大部分都是添加属性,然后加些简单的逻辑判断。
其实我更想说的是,有时候会要求你的页面改变状态,比如


image.png

要求登录的时候才显示右边,然后未登录是不显示的,比如这些动态的情况,如果布局是拼起来的话,一个一个改状态就很不容易管理,把它封装起来,变成一个整体的话,改状态就很方便。

所以我建议造这种小轮子的目的一是为了更快开发不做重复事情,二是为了方便管理。

相关文章

  • Android自定义菜单选择条目

    一.需求 有时候我们需要在项目里做一个菜单样式的功能,比如美团的 再比如JD的 有时候很多个app需要这样的UI,...

  • 公众号菜单可以直接点击拨号

    登录后选择“小程序管理”菜单。 搜索并添加小程序“电话码” 添加自定义菜单,“菜单内容”选择“跳转小程序”、选择小...

  • Android 自定义条目

    最近项目自定义的控件比较多,自己也学习了不少,以前觉得自定义很难,研究捣鼓了一段时间,感觉也就那么回事,无非是要计...

  • Xcode自定义代码块

    1.选中需要自定义的代码, 2.拖入代码块中,生成新的条目。 3.点击该条目,选择“Edit”,出现下图。 图示:

  • 软件技巧(7)---- Excel 使用技巧

    自定义功能区 在开始菜单栏右击,选择自定义功能区; 可以对菜单栏里面的功能组进行设定 冻结首行 选择视图==》冻结...

  • Idea 自定义菜单

    #IDEA自定义菜单# #IDEA# #自定义菜单# IDEA 自定义菜单 VCS 菜单 在VCS popu 里面...

  • Word自定义多级编号

    Word自定义多级编号 ​ 1. 自定义编号 在开始菜单中,选中编号,选择自定义编号,如下图所示。1.png 选择...

  • Flutter3.7版本新增组件-Menu菜单系列介绍

    之前Flutter的菜单选择、下拉菜单的支持非常简单且不友好,对于非常常见的下拉菜单选择功能是需要自己自定义实现,...

  • RecyclerView

    RecyclerView滑动监听 //上下文菜单获取条目索引

  • flutter 安卓打开应用白屏

    Android Studio配置:选择run/configurations 菜单,添加--enable-softw...

网友评论

本文标题:Android自定义菜单选择条目

本文链接:https://www.haomeiwen.com/subject/ewjluxtx.html