Android 纯代码布局编写手游sdk

前言 :

最近因为公司需求 上Google被查的很严, 所以就想着把代码重构 然后写布局也改成用代码写,所以就写了一个demo 然后我这边就想着 分享给各位同学

具体实现:

精简View的Base封装

-### 头部导航封装

标题文字

ini 复制代码
ls.gravity = Gravity.CENTER;
RelativeLayout titleLayout = new RelativeLayout(getContext());
//添加标题
mTitleTv = getTitleTv(getTitle());
titleLayout.addView(mTitleTv, ls);

左侧关闭

ini 复制代码
//关闭按钮
if(!TextUtils.isEmpty(backimagesrc)){

    backimage = new ImageView(getContext());
    //backimage.setPadding(_10dp, _5dp, _10dp, _5dp);
   //backimage.setBackground(DrawableUtils.createShape(1, C_COMFIRM));
    backimage.setImageResource(ImmpResourceUtil.getDrawableId(mContext,
            backimagesrc));
    RelativeLayout.LayoutParams backrl = new RelativeLayout.LayoutParams(_20dp, _20dp);
    backrl.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    backrl.leftMargin=_10dp;
    backrl.topMargin=_10dp;
    titleLayout.addView(backimage, backrl);
    backimage.setVisibility(View.VISIBLE);

    backimage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dismiss();
        }
    });

}

右侧关闭

ini 复制代码
// 右侧按钮

if(!TextUtils.isEmpty(closeimagesrc)){

    closeimage = new ImageView(getContext());
    closeimage.setPadding(_10dp, _5dp, _10dp, _5dp);
    closeimage.setImageResource(ImmpResourceUtil.getDrawableId(mContext,
            closeimagesrc));
    RelativeLayout.LayoutParams closerl = new RelativeLayout.LayoutParams(_20dp, _20dp);
    closerl.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    closerl.rightMargin = _10dp;
    closerl.topMargin = _10dp;
    titleLayout.addView(closeimage, closerl);
    closeimage.setVisibility(View.VISIBLE);

    closeimage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dismiss();

        }
    });
}
添加分割线和添加view到layout
ini 复制代码
ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
ls.gravity = Gravity.CENTER;
mParentView.addView(titleLayout, ls);

ls = new LinearLayout.LayoutParams(dp(25), dp(25));
ls.gravity = Gravity.CENTER;
ls.leftMargin = dp(5);
ls.topMargin = dp(5);

//添加分割线
mParentView.addView(addLine(getContext()), new LinearLayout.LayoutParams(MATCH_PARENT, dp(1)));//添加分割线

//添加内容
ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
ls.gravity = Gravity.CENTER;
ls.weight = 1;
mContentView = new LinearLayout(getContext());
mContentView.setOrientation(LinearLayout.VERTICAL);
mContentView.setGravity(Gravity.CENTER);
mContentView.setPadding(_10dp, 0, _10dp, _10dp);
setCanceledOnTouchOutside(false);
// setCancelable(false);
mParentView.addView(mContentView, ls);
setContentView(mParentView, new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));

完整SimpleBaseDialog代码

ini 复制代码
package com.lingyou.testfb.layout;

import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.text.InputType;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.*;
import com.lingyou.testfb.SimpleResultListener;
import com.lingyou.testfb.utils.DisplayUtils;
import com.lingyou.testfb.utils.DrawableUtils;
import com.lingyou.testfb.utils.ImmpResourceUtil;



/**
 * @author xuqing
 * @date :Created in 2021/4/25 0025 11:39
 * @description:精简View的Base封装
 */
public abstract class SimpleBaseDialog extends Dialog {
    protected final static int MATCH_PARENT = LinearLayout.LayoutParams.MATCH_PARENT;
    protected final static int WRAP_CONTENT = LinearLayout.LayoutParams.WRAP_CONTENT;

    protected final int _10dp = DisplayUtils.dip2Px(getContext(), 10);
    protected final int _5dp = DisplayUtils.dip2Px(getContext(), 5);
    protected final int _32dp = DisplayUtils.dip2Px(getContext(), 32);
    protected final int _20dp = DisplayUtils.dip2Px(getContext(), 20);

    public static final String C_COMFIRM = "#FF26ADF0";
    public static final String C_COMFIRM_P = "#DD26ADF0";
    public static final String C_CANCEL = "#FFCCCCCC";
    public static final String C_CANCEL_P = "#DDCCCCCC";

    public Context mContext;

    protected LinearLayout mParentView;
    protected LinearLayout mContentView;



    protected TextView mTitleTv;
    protected TextView closeBtn;
    protected ImageView backimage;
    protected ImageView closeimage;
    protected SimpleResultListener callbackListener;

    private  String backimagesrc;
    private  String closeimagesrc;



    public SimpleBaseDialog(Context context) {
        super(context);
        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        this.mContext = context;
        initView();
    }

    public SimpleBaseDialog( Context context,String backimagesrc) {
        super(context);
        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        this.mContext=context;
        this.backimagesrc=backimagesrc;
        initView();
    }



    public SimpleBaseDialog( Context context,String backimagesrc, String closeimagesrc) {
        super(context);
        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        this.mContext=context;
        this.backimagesrc=backimagesrc;
        this.closeimagesrc=closeimagesrc;
        initView();
    }


    protected void initView() {

        mParentView = new LinearLayout(getContext());
        mParentView.setOrientation(LinearLayout.VERTICAL);
        mParentView.setPadding(0, 0, _5dp, _5dp);
        mParentView.setBackground(DrawableUtils.createShape("#ffffff"));
        LinearLayout.LayoutParams ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);



        ls.gravity = Gravity.CENTER;
        RelativeLayout titleLayout = new RelativeLayout(getContext());
        //添加标题
        mTitleTv = getTitleTv(getTitle());
        titleLayout.addView(mTitleTv, ls);

        //关闭按钮
        if(!TextUtils.isEmpty(backimagesrc)){

            backimage = new ImageView(getContext());
            //backimage.setPadding(_10dp, _5dp, _10dp, _5dp);
           //backimage.setBackground(DrawableUtils.createShape(1, C_COMFIRM));
            backimage.setImageResource(ImmpResourceUtil.getDrawableId(mContext,
                    backimagesrc));
            RelativeLayout.LayoutParams backrl = new RelativeLayout.LayoutParams(_20dp, _20dp);
            backrl.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
            backrl.leftMargin=_10dp;
            backrl.topMargin=_10dp;
            titleLayout.addView(backimage, backrl);
            backimage.setVisibility(View.VISIBLE);

            backimage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dismiss();
                }
            });

        }

        // 右侧按钮

        if(!TextUtils.isEmpty(closeimagesrc)){

            closeimage = new ImageView(getContext());
            closeimage.setPadding(_10dp, _5dp, _10dp, _5dp);
            closeimage.setImageResource(ImmpResourceUtil.getDrawableId(mContext,
                    closeimagesrc));
            RelativeLayout.LayoutParams closerl = new RelativeLayout.LayoutParams(_20dp, _20dp);
            closerl.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            closerl.rightMargin = _10dp;
            closerl.topMargin = _10dp;
            titleLayout.addView(closeimage, closerl);
            closeimage.setVisibility(View.VISIBLE);

            closeimage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dismiss();

                }
            });
        }


        ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        ls.gravity = Gravity.CENTER;
        mParentView.addView(titleLayout, ls);

        ls = new LinearLayout.LayoutParams(dp(25), dp(25));
        ls.gravity = Gravity.CENTER;
        ls.leftMargin = dp(5);
        ls.topMargin = dp(5);

        //添加分割线
        mParentView.addView(addLine(getContext()), new LinearLayout.LayoutParams(MATCH_PARENT, dp(1)));//添加分割线

        //添加内容
        ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        ls.gravity = Gravity.CENTER;
        ls.weight = 1;
        mContentView = new LinearLayout(getContext());
        mContentView.setOrientation(LinearLayout.VERTICAL);
        mContentView.setGravity(Gravity.CENTER);
        mContentView.setPadding(_10dp, 0, _10dp, _10dp);
        setCanceledOnTouchOutside(false);
        // setCancelable(false);
        mParentView.addView(mContentView, ls);
        setContentView(mParentView, new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        initImpView();
    }


    public void changeTitle(String title) {
        if (mTitleTv != null) {
            mTitleTv.setText("" + title);
        }
    }

    protected void showCloseBtn(View.OnClickListener clickListener) {
        if (closeBtn != null) {
            closeBtn.setVisibility(View.VISIBLE);
            closeBtn.setOnClickListener(clickListener);
        }
    }

    protected TextView getTitleTv(String title) {
        TextView tv = new TextView(getContext());
        tv.setText("" + title);
        tv.setTextSize(16);
        //加粗
        TextPaint tp = tv.getPaint();
        tp.setFakeBoldText(true);
        tv.setMinHeight(dp(38));
        tv.setTextColor(0xff000000);
        tv.setGravity(Gravity.CENTER);
        return tv;
    }

    //改变父窗口的背景
    public void changeParentViewBackground(Drawable drawable) {
        if (mParentView != null) {
            mParentView.setBackground(drawable);
        }
    }

    //移除内容中的视图
    protected void removeContentView() {
        if (mContentView != null) {
            mContentView.removeAllViews();
        }
    }

    protected void addChild(ViewGroup parent, View child, int margintop) {
        LinearLayout.LayoutParams ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        ls.gravity = Gravity.CENTER;
        ls.topMargin = DisplayUtils.dip2Px(getContext(), margintop);
        parent.addView(child, ls);
    }

    protected void addChild(ViewGroup parent, View child, ViewGroup.LayoutParams layoutParams) {
        if (layoutParams == null) {
            layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        }
        if (parent != null) {
            parent.addView(child, layoutParams);
        }
    }


    protected void addView(View view) {
        LinearLayout.LayoutParams ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        ls.gravity = Gravity.CENTER;
        addView(view, ls);
    }


    protected void addView(View view, ViewGroup.LayoutParams layoutParams) {
        if (layoutParams == null) {
            layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        }
        if (mContentView != null) {
            mContentView.addView(view, layoutParams);


        }
    }

    protected void addView(View view, int margintopPx) {
        LinearLayout.LayoutParams ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        ls.gravity = Gravity.CENTER;
        ls.topMargin = margintopPx;
        if (mContentView != null) {
            mContentView.addView(view, ls);

        }

    }


    protected void addView(View view, int margintopPx,View leftView) {
        LinearLayout.LayoutParams ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        ls.gravity = Gravity.CENTER;
        ls.topMargin = margintopPx;
        if (mContentView != null) {
            mContentView.addView(leftView, ls);
            mContentView.addView(view, ls);
        }

    }


    protected void addView(View view, int margintopPx, View rightView,int marginPX) {
        LinearLayout.LayoutParams ls = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        ls.gravity = Gravity.CENTER;
        ls.topMargin = margintopPx;
        if (mContentView != null) {
            mContentView.addView(view, ls);
        }
    }



    protected TextView addTextView() {
        TextView tv = new TextView(getContext());
        tv.setTextColor(0xff222222);
        tv.setTextSize(12);
        tv.setGravity(Gravity.CENTER_VERTICAL);
        return tv;
    }

    protected View addLine(Context context) {
        View line = new View(context);
        line.setBackgroundColor(0xffeaeaea);
        return line;
    }

    //添加取消按钮
    protected Button addCancelBtn(String text) {
        Button cancelBtn = new Button(getContext());
        //cancelBtn.setTextSize(10);
        cancelBtn.setTextColor(Color.GRAY);
        cancelBtn.setBackground(DrawableUtils.createStateDrawable(_5dp, C_COMFIRM, C_COMFIRM_P));
        cancelBtn.setText(text);
        cancelBtn.setPadding(_5dp, _5dp, _5dp, _5dp);
        return cancelBtn;
    }

    protected Button addConfirmBtn(String text) {
        Button confirmBtn = new Button(getContext());
        confirmBtn.setTextColor(Color.WHITE);
        confirmBtn.setBackground(DrawableUtils.createStateDrawable(_5dp, C_COMFIRM, C_COMFIRM_P));
        confirmBtn.setText(text);
        confirmBtn.setPadding(_5dp, _5dp, _5dp, _5dp);
        return confirmBtn;
    }


    protected EditText addEditText() {
        EditText et = new EditText(getContext());
        et.setSingleLine();
        et.setMinHeight(_32dp);
        et.setGravity(Gravity.CENTER_VERTICAL);
        et.setPadding(dp(5), 5, dp(2), 0);
        et.setTextSize(dp(4));
        et.setTextColor(Color.GRAY);
        et.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
        et.setBackground(DrawableUtils.createShape(1, 10, -1, "#000000", "#ffffff"));
        return et;
    }

    protected abstract String getTitle();


    protected abstract void initImpView();

    protected int dp(int _dp) {
        return DisplayUtils.dip2Px(getContext(), _dp);
    }

    protected int sp(int sp) {
        return DisplayUtils.sp2px(getContext(), sp);
    }


    @Override
    public void show() {
        super.show();
        DisplayMetrics dmDisplayMetrics = new DisplayMetrics(); //为获取屏幕宽、高
        getWindow().getWindowManager().getDefaultDisplay().getMetrics(dmDisplayMetrics);
        android.view.WindowManager.LayoutParams p = this.getWindow().getAttributes(); //获取对话框当前的参数值
        p.gravity = Gravity.CENTER;

ViewGroup.LayoutParams.WRAP_CONTENT);
        this.getWindow().setLayout(DisplayUtils.dip2Px(getContext(), 300), DisplayUtils.dip2Px(getContext(), 300));
    }


}

注册界面实现:

ini 复制代码
package com.lingyou.testfb.layout;

import android.content.Context;
import android.os.Bundle;
import android.text.InputType;
import android.text.TextUtils;
import android.view.Gravity;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.lingyou.testfb.utils.DrawableUtils;
import com.lingyou.testfb.utils.ImmpResourceUtil;
import com.lingyou.testfb.utils.SPUtils;




/**
 * 作者:xuqing
 * 时间:2024年03月15日 15:55:27
 * 邮箱:1693891473@qq.com
 * 说明:注册界面
 */
public  class SimpleregisterDialog  extends SimpleBaseDialog{


    private EditText editAccount, editPwd,editnewpsw;
    protected LinearLayout editAccountiLlView,editPwdLlView,editnewpswLlView;
    private ImageView accountImage,editPwdImage,editnewpswImage;





    private  String backimagesrc;
    private  String closeimagesrc;
    private Context context;




    public SimpleregisterDialog(Context context) {
        super(context);
    }

    public SimpleregisterDialog(Context context, String backimagesrc) {
        super(context, backimagesrc);
    }

    public SimpleregisterDialog(Context context, String backimagesrc, String closeimagesrc) {
        super(context, backimagesrc, closeimagesrc);
    }

    @Override
    protected String getTitle() {
        return "快速注册";
    }



    @Override
    protected void initImpView() {

        editAccount = addEditText();
        editAccount.setHint("测试账号.");
        editAccount.setText((String) SPUtils.get(getContext(), "login_name", ""));
        LinearLayout.LayoutParams editAccountlayoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT);
        editAccount.setLayoutParams(editAccountlayoutParams);
        editAccountlayoutParams.setMargins(dip2px(15),0,0,0);




        accountImage = new ImageView(getContext());
        accountImage.setImageResource(ImmpResourceUtil.getDrawableId(mContext,
                "ddsrwc_user_icon"));
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( dip2px(20),  dip2px(20));
        accountImage.setLayoutParams(layoutParams);

        //账号线性布局
        editAccountiLlView=new LinearLayout(getContext());
        editAccountiLlView.setOrientation(LinearLayout.HORIZONTAL);
        editAccountiLlView.setGravity(Gravity.CENTER);
        editAccountiLlView.setPadding(0, 0, _5dp, _5dp);
        editAccountiLlView.setBackground(DrawableUtils.createShape("#ffffff"));
        editAccountiLlView.addView(accountImage,layoutParams);
        editAccountiLlView.addView(editAccount,editAccountlayoutParams);
        addView(editAccountiLlView, _10dp);



        //输入密码
        editPwd = addEditText();
        LinearLayout.LayoutParams  editPwdlayoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT);
        editPwd.setLayoutParams(editPwdlayoutParams);
        editAccountlayoutParams.setMargins(dip2px(15),0,0,0);
        editPwd.setGravity(Gravity.CENTER_VERTICAL);
        editPwd.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
        editPwd.setHint("请输入密码.");


        editPwdImage = new ImageView(getContext());
        editPwdImage.setImageResource(ImmpResourceUtil.getDrawableId(mContext,
                "ddsrwc_psd_img"));
        LinearLayout.LayoutParams   editPwdImagelayoutParams = new LinearLayout.LayoutParams( dip2px(20),  dip2px(20));
        editPwdImage.setLayoutParams(editPwdImagelayoutParams);

        //账号线性布局
        editPwdLlView=new LinearLayout(getContext());
        editPwdLlView.setOrientation(LinearLayout.HORIZONTAL);
        editPwdLlView.setGravity(Gravity.CENTER);
        editPwdLlView.setPadding(0, 0, _5dp, _5dp);
        editPwdLlView.setBackground(DrawableUtils.createShape("#ffffff"));
        editPwdLlView.addView(editPwdImage,editPwdImagelayoutParams);
        editPwdLlView.addView(editPwd,editAccountlayoutParams);
        addView(editPwdLlView, _10dp);



        editnewpsw = addEditText();
        LinearLayout.LayoutParams  editnewpswlayoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT);
        editnewpsw.setLayoutParams(editnewpswlayoutParams);
        editnewpswlayoutParams.setMargins(dip2px(15),0,0,0);
        editnewpsw.setGravity(Gravity.CENTER_VERTICAL);
        editnewpsw.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
        editnewpsw.setHint("请输入密码.");


        editnewpswImage = new ImageView(getContext());
        editnewpswImage.setImageResource(ImmpResourceUtil.getDrawableId(mContext,
                "ddsrwc_psd_img"));
        LinearLayout.LayoutParams  eeditnewpswImagelayoutParams = new LinearLayout.LayoutParams( dip2px(20),  dip2px(20));
        editnewpswImage.setLayoutParams(eeditnewpswImagelayoutParams);

        //账号线性布局
        editnewpswLlView=new LinearLayout(getContext());
        editnewpswLlView.setOrientation(LinearLayout.HORIZONTAL);
        editnewpswLlView.setGravity(Gravity.CENTER);
        editnewpswLlView.setPadding(0, 0, _5dp, _5dp);
        editnewpswLlView.setBackground(DrawableUtils.createShape("#ffffff"));
        editnewpswLlView.addView(editnewpswImage,eeditnewpswImagelayoutParams);
        editnewpswLlView.addView(editnewpsw,editnewpswlayoutParams);
        addView(editnewpswLlView, _10dp);



        LinearLayout btnLayout = new LinearLayout(getContext());
        btnLayout.setOrientation(LinearLayout.HORIZONTAL);
        btnLayout.setGravity(Gravity.CENTER);
        addView(btnLayout, _10dp);


        //添加登陆
        LinearLayout.LayoutParams   lp = new LinearLayout.LayoutParams(0, _32dp);
        lp.weight = 1;
        lp.leftMargin = _5dp;
        Button loginBtn = addConfirmBtn("注册");
        btnLayout.addView(loginBtn, lp);

        loginBtn.setOnClickListener(v -> {
            String mUserAccount = editAccount.getText().toString().trim();
            String mPassword = editPwd.getText().toString().trim();
            if (TextUtils.isEmpty(mUserAccount)) {
                Toast.makeText(getContext(), "账号不能为空,请输入", Toast.LENGTH_SHORT).show();
                return;
            }

            SPUtils.put(getContext(), "注册", mUserAccount);
            if (callbackListener != null) {
                Bundle bundle = new Bundle();
                bundle.putString("username", mUserAccount);
                // bundle.putString("token", EncryptUtils.md5(mUserAccount));
                callbackListener.onSuccess(bundle);
                dismiss();
            }
        });

        setOnCancelListener(dialog -> {
            if (callbackListener != null) {
                callbackListener.onFail(-1, "登陆取消");
            }
        });
    }

    public int dip2px(float dpValue) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);


    }

}

注册界面显示调用

ini 复制代码
SimpleregisterDialog simpleregisterDialog=new SimpleregisterDialog(context,"ddsrwc_back_icon");
simpleregisterDialog.show();

效果图

最后总结:

安卓的纯代码布局对比iOS纯代码确实要麻烦很多 但是也是可以写 弊端就是无法可视化预览 写起来效率低 好处就是缺少了xml 布局编译时候解析 然后再sdk打包的时候只需要打包java 代码即可 我们在坐马甲包的时候也可以做出更多差异化, 因为xml布局我们无法做过多的混淆和差异化。如果你觉得文章还不错麻烦给我三连 关注点赞和转发 谢谢

相关推荐
xiaoshiquan120641 分钟前
as强制过滤指定依赖版本库,解决该依赖不同版本冲突
android
2501_929157682 小时前
Switch 20.5.0系统最新PSP模拟器懒人包
android·游戏·ios·pdf
用户094 小时前
Kotlin Flow的6个必知高阶技巧
android·面试·kotlin
用户094 小时前
Flutter插件与包的本质差异
android·flutter·面试
用户094 小时前
Jetpack Compose静态与动态CompositionLocal深度解析
android·面试·kotlin
聆风吟º7 小时前
【Spring Boot 报错已解决】别让端口配置卡壳!Spring Boot “Binding to target failed” 报错解决思路
android·java·spring boot
非专业程序员Ping15 小时前
HarfBuzz概览
android·ios·swift·font
Jeled15 小时前
「高级 Android 架构师成长路线」的第 1 阶段 —— 强化体系与架构思维(Clean Architecture 实战)
android·kotlin·android studio·1024程序员节
明道源码17 小时前
Kotlin 控制流、函数、Lambda、高阶函数
android·开发语言·kotlin
消失的旧时光-194320 小时前
Kotlin × Gson:为什么遍历 JsonObject 要用 entrySet()
android·kotlin·数据处理·1024程序员节