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

自定义控件:用户名输入框

程序员文章站 2022-03-27 22:35:11
自定义控件之用户名输入框实现功能:存在删除按钮,可以进行直接删除存在展开下拉框按钮,可以展开保存过的用户名实现焦点改变是边框颜色的改变bug如下:欢迎大神帮忙改正输入内容过长时,文字会显示在删除按钮之下多行输入时,删除按钮被挤出可视范围多行输入时,焦点边框被挤出可视范围本文与之前的密码输入框是一套类型的控件,如有需要可参考如下:密码输入框......

自定义控件之用户名输入框

实现功能:

  1. 存在删除按钮,可以进行直接删除
  2. 存在展开下拉框按钮,可以展开保存过的用户名
  3. 实现焦点改变是边框颜色的改变

bug如下:欢迎大神帮忙改正

  1. 输入内容过长时,文字会显示在删除按钮之下
  2. 多行输入时,删除按钮被挤出可视范围
  3. 多行输入时,焦点边框被挤出可视范围

本文与之前的密码输入框是一套类型的控件,如有需要可参考如下:密码输入框

话不多说,看看具体代码吧,注释也很详细,就不在多解释了

package com.xxxx.Login;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;

import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatEditText;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.xxxx.cmis.R;

import java.util.ArrayList;
import java.util.List;


/**
 * 登陆界面的用户名输入框
 * 可下拉,可删除,可输入
 *
 * @author Charlie
 */
public class LoginUserNameEditText extends AppCompatEditText {
    private       Context      context;
    /**
     * 底部线的默认颜色
     */
    private       int          downLineDefaultColor;
    /**
     * 底部线获取焦点颜色
     */
    private       int          downLineFocusColor;
    /**
     * 底部线的画笔
     */
    private       Paint        downLinePaint;
    /**
     * 清除图片的画笔
     */
    private       Paint        clearPaint;
    /***
     * 右侧要显示的图片
     */
    private       Drawable     iconRightDrawable;
    /***
     * 显示下拉列表的图标
     */
    private       Bitmap       iconRightContent;
    /**
     * 清除内容图标
     */
    private       Bitmap       iconClear;
    /***
     * 是否获取焦点
     */
    private       boolean      hasFocus;
    /***
     * 是否展开下拉列表
     */
    private       boolean      isShow  = false;
    /***
     * 画出的两个图的间距
     */
    private final int          PADDING = 50;
    /***
     * 下拉内容的显示区域
     */
    private       PopupWindow  popupWindow;
    /***
     * 存放要显示的内容
     */
    private       List<String> list = new ArrayList<>();

    //定义一个接口,用于点击删除条目
    interface OnClearContentListener {
        void onClick(int position);
    }

    /***
     * 定义一个接口对象
     */
    private OnClearContentListener onClearContentListener;
	public void  setOnClearContentListener(OnClearContentListener onClearContentListener){
		this.onClearContentListener = onClearContentListener;
	}
    public LoginUserNameEditText(Context context) {
        this(context, null);
    }

    public LoginUserNameEditText(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.editTextStyle);
        this.context = context;
    }

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

    private void initIcon() {
        downLineDefaultColor = getResources().getColor(R.color.down_line_default_color);
        downLineFocusColor = getResources().getColor(R.color.down_line_focus_color);
        if (isShow) {
        // △下拉框打开时的图标
            iconRightDrawable = getResources().getDrawable(R.drawable.ic_hint_user_names);
        } else {
        // 倒△下拉框隐藏时的图标
            iconRightDrawable = getResources().getDrawable(R.drawable.ic_show_user_names);
        }
        iconRightContent = svgToBitmap(iconRightDrawable);
        iconClear = svgToBitmap(getResources().getDrawable(R.drawable.ic_clear_content));
        setBackground(null);
        initPaint();
    }

    private void initPaint() {
        downLinePaint = new Paint();
        downLinePaint.setColor(downLineDefaultColor);
        downLinePaint.setStrokeWidth(dp2px(1));
        downLinePaint.setAntiAlias(true);

        clearPaint = new Paint();
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        hasFocus = focused;
        if (!focused) {
            //失去焦点时
            isShow = false;
        }
        // 控件获取焦点时改变底部线的颜色
        downLinePaint.setColor(focused ? downLineFocusColor : downLineDefaultColor);
        invalidate();//更新视图
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (isShow) {
            iconRightDrawable = getResources().getDrawable(R.drawable.ic_hint_user_names);
        } else {
            iconRightDrawable = getResources().getDrawable(R.drawable.ic_show_user_names);
        }
        //绘制右侧图标
        setCompoundDrawablesWithIntrinsicBounds(getCompoundDrawables()[0], getCompoundDrawables()[1], iconRightDrawable, getCompoundDrawables()[3]);
        //距离控件左侧的距离 ( 后面的数字是两个图片之间的间隔)
        int left = getWidth() - iconRightContent.getWidth() - iconClear.getWidth() - PADDING;
        //距离控件顶部的距离
        int top = (getHeight() - iconClear.getHeight()) / 2;
        if (hasFocus && getText().length() > 0) {
            //文字内容不为空时,显示删除图标
            canvas.drawBitmap(iconClear, left, top, clearPaint);
        }
        // 绘制底部的线
        canvas.drawLine(getScrollX(), this.getHeight() - dp2px(1), getScrollX() + this.getWidth(), this.getHeight() - dp2px(1), downLinePaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            int eventX = (int) event.getX();//触摸点左上角x坐标,相对于控件本身的坐标
            int eventY = (int) event.getY();
            //触摸按下时
            if (getCompoundDrawables()[2] != null) {
                //右侧存在图片
                // getTotalPaddingRight 图片左侧距离控件右边框的距离
                Boolean isInnerWidth = eventX > (getWidth() - getTotalPaddingRight() - PADDING / 2) && eventX < getWidth();
                Boolean isInnerHeight = eventY > 0 && eventY < getHeight();
                if (isInnerHeight && isInnerWidth) {
                    // 触摸在了显示内容的图标上
                    isShow = !isShow;
                    showPopupWindow();
                    invalidate();
                    return false;
                } else {
                    isShow = false;
                    if (popupWindow != null && popupWindow.isShowing()) {
                        popupWindow.dismiss();
                    }
                }
            }
            // 清空图片左侧距离控件左侧的距离
            int left = getWidth() - iconRightContent.getWidth() - iconClear.getWidth() - PADDING;
            Boolean isWidth = eventX > left && eventX < (getWidth() - iconRightContent.getWidth() - PADDING / 2);
            Boolean isHeight = eventY > 0 && eventY < getHeight();
            if (isWidth && isHeight) {
                //触摸在清空图片上
                setText("");
                invalidate();
                return false;
            }
        }
        return super.onTouchEvent(event);
    }

    private int sp2px(float spValue) {
        float spDensity = getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * spDensity + 0.5f);
    }

    /***
     * dp转成px
     * @param dip
     * @return
     */
    private int dp2px(double dip) {
        float dpDensity = getContext().getResources().getDisplayMetrics().density;
        return (int) (dip * dpDensity + 0.5);
    }

    /***
     * svg矢量图转成Bitmap
     * @param drawable
     * @return
     */
    private Bitmap svgToBitmap(Drawable drawable) {
        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        drawable.draw(canvas);
        return bitmap;
    }

    /***
     * 打开显示内容区域
     */
    private void showPopupWindow() {
        if (popupWindow != null && popupWindow.isShowing()) {
            popupWindow.dismiss();
            return;
        }
        View view = inflate(context, R.layout.layout_login_show_username, null);
        int height = getLayoutParams().height;
        if (list.size() > 0) {
            if (list.size() < 5) {
                popupWindow = new PopupWindow(view, getWidth(), ViewGroup.LayoutParams.WRAP_CONTENT);
            } else {
                popupWindow = new PopupWindow(view, getWidth(), height * 5);
            }
        } else {
            popupWindow = new PopupWindow(view, getWidth(), getLayoutParams().height);
        }
        RecyclerView recyclerView = view.findViewById(R.id.recycle_login_show_username);
        recyclerView.setLayoutManager(new LinearLayoutManager(context));
        recyclerView.setAdapter(new PopupWindowShowContentAdapter());
        view.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (popupWindow != null && popupWindow.isShowing()) {
                    popupWindow.dismiss();
                    isShow = false;
                    popupWindow = null;
                }
                return false;
            }
        });
        popupWindow.showAsDropDown(this);
    }

	/**通过这个方法设置下拉框要显示的内容*/
    public void setShowContext(List<String> list) {
        this.list = list;
    }

    class PopupWindowShowContentAdapter extends RecyclerView.Adapter<ViewHolder> {

        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = inflate(context, R.layout.item_login_show_username, null);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.textView.setText(list.get(position));
            holder.linearLayout.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    setText(list.get(position));
                    isShow = false;
                    popupWindow.dismiss();
                }
            });
            holder.imageView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (onClearContentListener != null) {
                        onClearContentListener.onClick(position);
                        isShow = false;
                        popupWindow.dismiss();
                    }
                }
            });
        }

        @Override
        public int getItemCount() {
            return list == null ? 0 : list.size();
        }
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        LinearLayout linearLayout;
        TextView     textView;
        ImageView    imageView;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            linearLayout = itemView.findViewById(R.id.ll_item_login_show_username);
            textView = itemView.findViewById(R.id.tv_login_show_username);
            imageView = itemView.findViewById(R.id.img_clear_username);
        }
    }
}

下拉框的布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/show_user_name_background">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycle_login_show_username"
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

recycleview条目布局如下

<?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:id="@+id/ll_item_login_show_username"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/show_user_name_background"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_login_show_username"
            style="@style/TextFontStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingVertical="15dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="@string/text_username_hint"
            android:textColor="@color/tv_color_black"
            android:textSize="@dimen/text_size_16sp" />

        <ImageView
            android:id="@+id/img_clear_username"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:paddingHorizontal="5dp"
            app:srcCompat="@drawable/ic_clear_content" />
    </LinearLayout>


    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/tv_color_white" />
</LinearLayout>

本文地址:https://blog.csdn.net/weixin_43858255/article/details/107931716