一、 从“搬砖”到“建筑师”:为什么要控制UI界面?
记得我刚学Android那会儿,天天在XML里“搬砖”,感觉自己就是个没有感情的拖控件机器。直到有一天,产品经理拿着设计稿过来:“小王啊,这个按钮能不能根据用户心情变色?”
我:“……”
那一刻我悟了——只会写XML的Android程序员,就像只会用美图秀秀的设计师。真正的狠人,都是在代码里掌控UI的“控制狂”!
为什么要在代码中控制UI?
- 动态性是王道:用户点赞后爱心要放大?数据加载时需要进度条?这些XML都搞不定
- 代码复用:把UI构建逻辑封装成方法,一次编写,到处使用
- 极致性能:避免解析XML的开销,尤其在大规模动态更新时
- 逻辑清晰:UI创建和业务逻辑放在一起,维护起来更方便
说白了,XML布局就像预制菜,方便但缺乏灵魂;代码创建UI就像亲自下厨,想加什么料随你便!
二、 基础操作:View的“出生证明”
创建一个Button的两种姿势:
姿势一:XML里声明(常规操作)
<Button
android:id="@+id/my_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点我啊" />
姿势二:代码里“生”一个(控制狂专属)
// 在Activity中
public class MainActivity extends AppCompatActivity {
private LinearLayout mainLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 先创建父容器
mainLayout = new LinearLayout(this);
mainLayout.setOrientation(LinearLayout.VERTICAL);
// 创建Button并设置属性
Button myBtn = new Button(this);
myBtn.setText("我是代码生的按钮!");
myBtn.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
));
// 添加到父容器
mainLayout.addView(myBtn);
setContentView(mainLayout);
}
}
看到没?在代码里,每个View都是你亲手“捏”出来的,那种掌控感,XML给不了!
设置点击事件的进化史:
远古时代(匿名内部类):
myBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "考古代码", Toast.LENGTH_SHORT).show();
}
});
现代写法(Lambda表达式):
myBtn.setOnClickListener(v -> {
Toast.makeText(this, "时尚代码", Toast.LENGTH_SHORT).show();
});
三、 混合模式:XML与代码的“黄金搭档”
纯代码写UI虽然爽,但全屏控件都代码写也太累了。这时候就需要混合模式:
public class HybridActivity extends AppCompatActivity {
private TextView titleText;
private Button actionBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hybrid); // 先加载XML骨架
// 找到XML中的控件
titleText = findViewById(R.id.title_text);
actionBtn = findViewById(R.id.action_btn);
// 动态修改属性
titleText.setText("我是动态标题");
titleText.setTextColor(Color.RED);
// 动态添加新控件
LinearLayout container = findViewById(R.id.container);
Button dynamicBtn = new Button(this);
dynamicBtn.setText("动态添加的按钮");
container.addView(dynamicBtn);
}
}
这种模式就像:XML负责搭建舞台,代码负责导演节目,各司其职,完美!
四、 自定义View:成为UI界的“造物主”
当系统控件无法满足你的奇葩需求时,就该自定义View出场了!
打造一个会变色的ProgressBar:
public class MoodProgressBar extends View {
private int progress;
private int maxProgress = 100;
private Paint progressPaint;
private Paint bgPaint;
public MoodProgressBar(Context context) {
super(context);
init();
}
private void init() {
// 初始化背景画笔
bgPaint = new Paint();
bgPaint.setColor(Color.GRAY);
// 初始化进度条画笔
progressPaint = new Paint();
updateProgressColor();
}
// 根据进度改变颜色
private void updateProgressColor() {
float ratio = (float) progress / maxProgress;
int red = (int) (255 * ratio);
int green = (int) (255 * (1 - ratio));
progressPaint.setColor(Color.rgb(red, green, 0));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 画背景
canvas.drawRect(0, 0, getWidth(), getHeight(), bgPaint);
// 画进度
float progressWidth = getWidth() * progress / (float) maxProgress;
canvas.drawRect(0, 0, progressWidth, getHeight(), progressPaint);
}
public void setProgress(int progress) {
this.progress = progress;
updateProgressColor();
invalidate(); // 重绘视图
}
}
使用这个自定义View:
MoodProgressBar progressBar = new MoodProgressBar(this);
progressBar.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, 50
));
progressBar.setProgress(30); // 显示30%进度,颜色偏绿
看到没?从使用者变成创造者,这种感觉不要太爽!
五、 实战:打造智能登录界面
来,咱们搞个完整的登录界面,展示真正的技术:
public class SmartLoginActivity extends AppCompatActivity {
private LinearLayout rootLayout;
private EditText usernameEditText, passwordEditText;
private Button loginButton;
private ProgressBar loadingProgress;
private int attemptCount = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createUIProgrammatically();
setupEventHandlers();
}
private void createUIProgrammatically() {
// 创建根布局
rootLayout = new LinearLayout(this);
rootLayout.setOrientation(LinearLayout.VERTICAL);
rootLayout.setPadding(100, 100, 100, 100);
rootLayout.setBackgroundColor(Color.WHITE);
// 创建标题
TextView title = new TextView(this);
title.setText("智能登录");
title.setTextSize(24);
title.setTextColor(Color.BLACK);
title.setGravity(Gravity.CENTER);
rootLayout.addView(title);
// 创建用户名输入框
usernameEditText = new EditText(this);
setupEditText(usernameEditText, "请输入用户名");
rootLayout.addView(usernameEditText);
addVerticalMargin(30);
// 创建密码输入框
passwordEditText = new EditText(this);
setupEditText(passwordEditText, "请输入密码");
passwordEditText.setInputType(
InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
);
rootLayout.addView(passwordEditText);
addVerticalMargin(50);
// 创建登录按钮
loginButton = new Button(this);
loginButton.setText("登录");
loginButton.setBackgroundColor(Color.BLUE);
loginButton.setTextColor(Color.WHITE);
rootLayout.addView(loginButton);
addVerticalMargin(20);
// 创建加载进度条(初始隐藏)
loadingProgress = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
loadingProgress.setVisibility(View.GONE);
rootLayout.addView(loadingProgress);
setContentView(rootLayout);
}
private void setupEditText(EditText editText, String hint) {
editText.setHint(hint);
editText.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
));
}
private void addVerticalMargin(int dp) {
View space = new View(this);
space.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
(int) (dp * getResources().getDisplayMetrics().density)
));
rootLayout.addView(space);
}
private void setupEventHandlers() {
loginButton.setOnClickListener(v -> attemptLogin());
// 实时监听输入变化
TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
updateLoginButtonState();
}
@Override
public void afterTextChanged(Editable s) {}
};
usernameEditText.addTextChangedListener(textWatcher);
passwordEditText.addTextChangedListener(textWatcher);
}
private void updateLoginButtonState() {
boolean hasUsername = !usernameEditText.getText().toString().trim().isEmpty();
boolean hasPassword = !passwordEditText.getText().toString().trim().isEmpty();
loginButton.setEnabled(hasUsername && hasPassword);
loginButton.setAlpha(hasUsername && hasPassword ? 1.0f : 0.5f);
}
private void attemptLogin() {
attemptCount++;
// 显示加载
loadingProgress.setVisibility(View.VISIBLE);
loginButton.setEnabled(false);
// 模拟网络请求
new Handler().postDelayed(() -> {
loadingProgress.setVisibility(View.GONE);
loginButton.setEnabled(true);
if (attemptCount % 2 == 0) {
showSuccessAnimation();
} else {
showErrorAnimation();
}
}, 2000);
}
private void showSuccessAnimation() {
loginButton.setText("登录成功!");
loginButton.setBackgroundColor(Color.GREEN);
new Handler().postDelayed(() -> {
loginButton.setText("登录");
loginButton.setBackgroundColor(Color.BLUE);
}, 1500);
}
private void showErrorAnimation() {
loginButton.setText("登录失败,重试中...");
loginButton.setBackgroundColor(Color.RED);
// 抖动动画
ObjectAnimator animator = ObjectAnimator.ofFloat(
loginButton, "translationX", 0, 30, -30, 30, -30, 0
);
animator.setDuration(500);
animator.start();
new Handler().postDelayed(() -> {
loginButton.setText("登录");
loginButton.setBackgroundColor(Color.BLUE);
}, 1500);
}
}
这个登录界面牛在哪?
- 实时验证:输入框有内容时按钮才可用
- 视觉反馈:不同状态有颜色变化和动画
- 用户体验:加载状态、成功/失败状态一目了然
- 完全代码控制:动态创建所有UI元素
六、 性能优化:不做UI界的“败家子”
代码控制UI虽好,但用不好也会卡成PPT。记住这些优化技巧:
- 避免过度绘制:背景色不要层层重叠
- 使用ViewStub:延迟加载不立即显示的视图
- 回收利用:列表项使用ViewHolder模式
- 减少布局嵌套:能用RelativeLayout就别层层LinearLayout
// 好习惯:复用LayoutParams
LinearLayout.LayoutParams commonParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
TextView text1 = new TextView(this);
text1.setLayoutParams(commonParams);
TextView text2 = new TextView(this);
text2.setLayoutParams(commonParams); // 复用,节省内存
七、 结语:从UI工人到界面艺术家
兄弟们,掌握Android UI代码控制,就像画家从临摹到创作的蜕变。XML是你的素描本,代码才是你的调色盘。
记住:
- 简单布局用XML:快速高效
- 动态效果用代码:灵活掌控
- 复杂组件自定义:彰显实力
- 性能优化记心中:用户体验至上
别再满足于在XML里拖拖拽拽了,拿起代码的画笔,成为真正的UI艺术家吧!当你看到自己亲手创造的界面在手机上流畅运行,那种成就感,绝对值得你今天的付出。

被折叠的 条评论
为什么被折叠?



