首页 > 其他分享 >Android——自定义组件

Android——自定义组件

时间:2023-11-14 22:25:48浏览次数:37  
标签:自定义 int FlowLayout add child 组件 Android data public

自定义组件共分为:自定义组合控件,自定义View,自定义ViewGroup

自定义ViewGroup一共七步:

  1.继承ViewGroup,将统一调用第三的构造方法。重写onMeasure(),onLayout()方法,创建数据集合对象,创建孩子行列集合对象。编写常量横向外边距,纵向外边距,组件属性  

  2.创建孩子,设置孩子,添加孩子

  3.测量孩子,测量自己,行列分布

  4.布局孩子,外边距使用

  5.编写逻辑

  6.暴露接口

  7.暴露属性

 

方法:

  removeAllViews():删除ViewGroup所有孩子

  addView(View view):添加孩子

  getChild(int index):获取指定位置的孩子

  measureChild(View child, int widthMeasureSpace, int heightMeasureSpace):测量孩子

  MeasureSpec.getSize(int width):获取size

  MeasureSpec.makeMeasureSpec(int width, MeasureSpec.AT_MOST):创建MeasureSpec

  view.getMeasureWidth():测量后可调用,获取组件宽度 

具体代码:

  1. 工具代码SizeUtil.java,App.java

public class SizeUtils {
    public static int dip2px(float dpValue){
        float scale = LitePalApplication.getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}
public class App extends Application {
    private static Context mContext = null;
    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }
    public static Context getAppContext() {
        return mContext;
    }
}

 

  2.FlowLayout.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="汉堡包"
    android:paddingLeft="20dp"
    android:paddingRight="20dp"
    android:paddingTop="10dp"
    android:paddingBottom="10dp"
    android:textColor="@color/text_grey"
    android:background="@drawable/selector_flow_test">

</TextView>

 

  3.FlowLayout.java

public class FlowLayout extends ViewGroup {
    private List<List<View>> allLineList = new ArrayList<>();
    private List<String> dataList = new ArrayList<>();
    private static final int DEFAULT_HORIZON_MARGIN = SizeUtil.dip2px(5);
    private static final int DEFAULT_VERTICAL_MARGIN = SizeUtil.dip2px(5);
    private static final int DEFAULT_CHILD_MAX_LINE = 3;
    private static final float DEFAULT_CHILD_TEXT_SIZE = 8;
    private float childTextSize;
    private int childMaxLine;

    public FlowLayout(Context context) {
        this(context, null);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
        childTextSize = typedArray.getDimension(R.styleable.FlowLayout_childTextSize, DEFAULT_CHILD_TEXT_SIZE);
        childMaxLine = typedArray.getInt(R.styleable.FlowLayout_childMaxLine, DEFAULT_CHILD_MAX_LINE);
        typedArray.recycle();
    }

    // 2. 创建孩子,设置孩子,添加孩子
    public void setDataList(List<String> dataList ){
        removeAllViews();
        this.dataList.clear();
        this.dataList.addAll(dataList);
        for (String data : this.dataList) {
            TextView child = (TextView)LayoutInflater.from(getContext()).inflate(R.layout.item_flow_text, this, false);
            child.setText(data);
            child.setTextSize(childTextSize);
            addView(child);
        }
    }

    // 3.测量孩子,测量自己,行列分布
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int parentWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeightSize = MeasureSpec.getSize(heightMeasureSpec);
        int childWidthSize = MeasureSpec.makeMeasureSpec(parentWidthSize, MeasureSpec.AT_MOST);
        int childHeightSize = MeasureSpec.makeMeasureSpec(parentHeightSize,MeasureSpec.AT_MOST);
        if( getChildCount() == 0 ){
            return;
        }
        allLineList.clear();
        List<View> lineList = new ArrayList<>();
        allLineList.add(lineList);

        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            final  int j = i;
            child.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onItemClickListener != null) {
                        onItemClickListener.onItemClick(child,dataList.get(j),j);
                    }
                }
            });
            measureChild(child,childWidthSize,childHeightSize);

            if( lineList.size() == 0 ){
                lineList.add(child);
            }else {
                if( allLineList.size() == childMaxLine){
                    break;
                }
                    int totalLineWidth = 0;
                for (View view : lineList) {
                    totalLineWidth += view.getMeasuredWidth() + DEFAULT_HORIZON_MARGIN;
                }
                if( totalLineWidth + child.getMeasuredWidth() + DEFAULT_HORIZON_MARGIN <= parentWidthSize){
                    lineList.add(child);
                }else {
                    lineList = new ArrayList<>();
                    lineList.add(child);
                    allLineList.add(lineList);
                }
            }
        }

        int targetHeightSize = (getChildAt(0).getMeasuredHeight() + DEFAULT_HORIZON_MARGIN) * allLineList.size();
        setMeasuredDimension(parentWidthSize,targetHeightSize);
    }

    // 4.布局孩子,外边距通过layout画出
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if( getChildCount() == 0 ){
            return;
        }
        int currentLeft = DEFAULT_HORIZON_MARGIN;
        int currentTop = 0;
        int currentRight = 0;
        int currentBottom = getChildAt(0).getMeasuredHeight();
        for (List<View> lineList : allLineList) {
            for (View child : lineList) {
                currentRight = currentLeft + child.getMeasuredWidth();
                child.layout(currentLeft,currentTop,currentRight,currentBottom);
                currentLeft = currentRight + DEFAULT_HORIZON_MARGIN;
            }
            currentLeft = 0;
            currentRight = 0;
            currentTop = currentBottom + DEFAULT_VERTICAL_MARGIN;
            currentBottom = currentTop + getChildAt(0).getMeasuredHeight();
        }
    }

    public interface OnItemClickListener {
        public void onItemClick(View view ,String data,int position);
    }
    private OnItemClickListener onItemClickListener;

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }
}

 

  4.FlowLayoutActivity.java,FlowLayout.xml

public class FlowLayoutActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flow_layout);
        List<String> data = new ArrayList<>();
        data.add("键盘");
        data.add("显示器");
        data.add("鼠标");
        data.add("ipad");
        data.add("air pod");
        data.add("Android手机");
        data.add("mac pro");
        data.add("大疆mini3 pro");
        data.add("ChatGPT");
        data.add("耳机");
        data.add("Noval AI");
        data.add("键盘");
        data.add("显示器");
        data.add("鼠标");
        data.add("键盘");
        data.add("显示器");
        data.add("鼠标");
        data.add("ipad");
        data.add("air pod");
        data.add("Android手机");
        data.add("mac pro");
        data.add("大疆mini3 pro");
        data.add("ChatGPT");
        data.add("耳机");
        data.add("Noval AI");
        data.add("键盘");
        data.add("显示器");
        data.add("鼠标");
        FlowLayout flowLayout = this.findViewById(R.id.flow_layout);
        flowLayout.setTextList(data);

        flowLayout.setOnItemClickListener(new FlowLayout.OnItemClickListener() {
            @Override
            public void onItemClickListener(View v, String text) {
                Toast.makeText(FlowLayoutActivity.this,"text "+text,Toast.LENGTH_SHORT).show();

            }
        });
    }

    private static final String TAG = "FlowLayoutActivity";
}
<?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=".flow.FlowLayoutActivity">

    <com.example.myandroiddemo.flow.FlowLayout
        android:id="@+id/flow_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="10dp" />
    
</LinearLayout>

 

  

 

标签:自定义,int,FlowLayout,add,child,组件,Android,data,public
From: https://www.cnblogs.com/remix777/p/17832703.html

相关文章

  • 自定义 Git Hook
    前言前端同学大概都熟悉husky这个工具,他可以直接在项目中添加githooks,主要解决了githooks不会同步到git仓库的问题,保证了每个开发人员的本地仓库都能执行相同的githooks。但是husky毕竟是一个JS生态的工具,依赖于npm安装和npm的scripthook才能达到最佳效果......
  • 基于element-ui开发组件自行制作的翻页小组件
    表格展示区<el-table:data="dis"style="width:100%;height:525px;"></el-table>翻页区<to-page:value="{page:tableData.length,current_page:current_page}"@......
  • Vue 组件里的定时器要怎么销毁?
    如果页面上有很多定时器,可以在data选项中创建一个对象timer,给每个定时器取个名字一一映射在对象timer中,在beforeDestroy构造函数中清除,beforeDestroy(){ for(letkinthis.timer){ clearInterval(k) }}如果页面只有单个定时器,可以这么做consttimer=setInterv......
  • Android安卓 match_parent与match_parent区别
    Android安卓match_parent与match_parent区别 在Android中,match_parent和fill_parent是布局参数(layoutparameters)中的两个常用属性,它们在XML中用于定义一个视图(View)的尺寸。在最新的Android版本中,fill_parent已经被废弃,而match_parent用于替代。**match_parent:**这个属......
  • Android安卓gravity和layout_gravity的区别
    在Android中,gravity和layout_gravity是用于控制视图元素在布局中位置的两个属性,它们有不同的作用和适用范围。gravity:gravity是用于设置视图元素内部内容(文本、图像等)在视图本身内的对齐方式。它影响的是视图内部内容的位置。<TextViewandroid:layout_width="wrap_conte......
  • Android 11 (MTK)状态栏图标反色-->跟随当前应用变化代码流程
    //StatusBar.javapublicvoidstart(){.............onSystemBarAppearanceChanged(mDisplayId,result.mAppearance,result.mAppearanceRegions,result.mNavbarColorManagedByIme);mAppFullscreen=result.mAppFullscreen;......
  • Vue3调用Element-plus涉及子组件v-model双向绑定props问题
    Vue3调用Element-plus涉及子组件v-model双向绑定props问题在Vue3调用Element-plus的el-dialog组件时,碰到个很有意思的问题,el-dialog的属性值v-model直接控制对话框的显示与否,点击关闭对话框和遮罩区域,组件内部会自动更改v-model的值为false来关闭对话框。问题在于当组件作为子组......
  • 动作活体检测能力支持自定义扫描动作,开发者接入更高效
    随着人脸识别技术在金融、医疗等多个领域的加速落地,网络安全、信息泄露等问题愈为突出,用户对应用稳定性和安全性的要求也更为严格。华为机器学习服务的动作活体检测能力,支持实时捕捉人脸,根据用户配合做动作可以判断是真实活体,还是非活体攻击(比如:翻拍图片、翻拍视频以及面具等)。......
  • 使用JWT、拦截器与ThreadLocal实现在任意位置获取Token中的信息,并结合自定义注解实现
    1.简介1.1JWTJWT,即JSONWebToken,是一种用于在网络上传递声明的开放标准(RFC7519)。JWT可以在用户和服务器之间传递安全可靠的信息,通常用于身份验证和信息交换。声明(Claims):JWT包含一组称为声明的信息,声明描述了一些数据。有三种类型的声明:注册声明(RegisteredClaims):这是......
  • 树形/级联组件->数据做键,制作与还原
    数据的制作/**树形/级联组件->数据做键,制作与还原*@param{Array}list*@param{string}params源`json`的`key`*@param{string}key生成后`string`存放的`key`*@param{string}children下一级的`key`值*@returns*/exportconstTreeValueToKe......