Кнопка Android расширяет - доступ к членам из Java в XML
Я новичок в программировании Android и хотел бы расширить класс кнопки, чтобы я мог добавить настраиваемое поле для кнопки, а затем изменить способ отображения кнопки в зависимости от поля. Я сделал несколько уроков, хорошо поработал, и у меня есть что-то, что компилируется, но не работает - поэтому я ищу советы о том, где я ошибся.
То, чего я хотел бы достичь, является более сложным, чем мой пример, но как только я смогу заставить этот пример работать, я думаю, у меня будет хороший шанс получить все остальное и приступить к работе.
Для моего примера я бы хотел, чтобы кнопка имела логический член / атрибут isRed. Если элемент задан, то мы меняем нарисованный прямоугольник на кнопке на красный цвет, если он ложный, то нарисованный зеленый.
Для этого у меня есть:
- создал файл redbutton.xml в моей директории res / drawable. Этот файл состоит из селектора, который предоставляет красный или зеленый прямоугольник, в зависимости от состояния isRed.
- создал файл RedButton.java в моем каталоге src / com.example.redbutton. Этот файл содержит класс RedButton, расширяющий Button
- создал файл attrs.xml в моей директории res / values. Это перечисляет член / атрибуты isRed
- поставить две кнопки в моем основном макете. Одна кнопка имеет значение custom: для isRed установлено значение true, для другой - значение isRed.
В теории у меня должно быть две кнопки в приложении: красная, зеленая. К сожалению, у меня есть две зеленые кнопки! Я не могу получить
<item custom:isRed="true">
в redbutton.xlm для оценки истинности. Однако, если я изменю эту строку на
<item android:state_pressed="true">
тогда у меня есть красная кнопка всякий раз, когда я нажимаю кнопку. Мне кажется, проблема в том, что доступ к моему настраиваемому полю всегда оценивается как ложный!
Ниже приведен код, который я написал. Кто-нибудь может дать мне несколько советов о том, что я сделал неправильно?
redbutton.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.example.redbutton" >
<!-- if the isred value is true, then make the background red -->
<!-- <item android:state_pressed="true"> -->
<item custom:isred="true" >
<shape android:shape="rectangle" >
<size android:width="100dp"
android:height="100dp"/>
<solid android:color="#ff0000"/>
</shape>
</item>
<!-- otherwise make it green -->
<item >
<shape android:shape="rectangle" >
<size android:width="100dp"
android:height="100dp"/>
<solid android:color="#00ff00"/>
</shape>
</item>
</selector>
RedButton.java
package com.example.redbutton;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.Button;
public class RedButton extends Button
{
private boolean mIsRed;
public RedButton (Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.RedButton,
0, 0);
try {
mIsRed = a.getBoolean(R.styleable.RedButton_isred, false);
} finally {
a.recycle();
}
}
//sets and gets for members
public boolean getIsRed()
{
return mIsRed;
}
public void setIsRed(boolean isRed)
{
mIsRed = isRed;
}
}
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RedButton">
<attr name="isred" format="boolean" />
</declare-styleable>
</resources>
fragment_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.example.redbutton"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.redbutton.MainActivity$PlaceholderFragment" >
<com.example.redbutton.RedButton
android:id="@+id/Button1"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="RedButton"
android:textSize="30sp"
custom:isred="true"
android:drawableBottom="@drawable/redbutton"
/>
<com.example.redbutton.RedButton
android:id="@+id/Button2"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="GreenButton"
android:textSize="30sp"
custom:isred="false"
android:drawableBottom="@drawable/redbutton"
/>
</LinearLayout>
2 ответа
Твой вопрос совершенно неясен. Самое большее, что я мог сделать сейчас, это просто угадать, чего ты хочешь достичь.
Вы хотите иметь кнопку, которая имеет цвет по умолчанию, когда она еще не нажата, а затем меняется на красный или зеленый? Если это так, то вот пример приложения для вас.
Приложение имеет 3 кнопки: одну с именем Red, одну с именем Green и одну с именем switch. Нажмите Красный и Зеленый, чтобы увидеть изменение фона со стандартного на выбранный цвет. Если вы нажмете переключатель, кнопка изменит цвет на противоположный (с зеленого на красный или с красного на зеленый)
package com.example.buttontest;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Button;
public class ColoredButton extends Button {
private boolean isRed = true;
public ColoredButton(Context context) {
super(context);
}
public ColoredButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ColoredButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setIsRed(boolean isRed) {
this.isRed = isRed;
changeBgColor();
}
private void changeBgColor() {
setBackgroundResource(isRed ? R.drawable.bg_red : R.drawable.bg_green);
setText(isRed? "Red" : "Green");
}
}
файл main.xml: обратите внимание, что тег xml для красной и зеленой кнопок ссылается на ColoredButton
учебный класс. Это потому, что вы собираетесь получить ClassCastException
если вы попытаетесь использовать общий Button
учебный класс. обратитесь к этому для получения дополнительной информации.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.buttontest.MainActivity" >
<com.example.buttontest.ColoredButton
android:id="@+id/btnRed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Red" />
<com.example.buttontest.ColoredButton
android:id="@+id/btnGreen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Green" />
<Button
android:id="@+id/btnSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch Color" />
</LinearLayout>
Теперь вам нужно создать два отдельных нарисованных XML-файла. Как сказал Кристофер, вы не можете просто создавать теги XML самостоятельно. Android не распознает их.
<?xml version="1.0" encoding="utf-8"?>
<!-- Name this file bg_green.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><color android:color="#00ff00" />
</item>
<item android:drawable="@android:drawable/btn_default"></item>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<!-- Name this file bg_red.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><color android:color="#ff0000" />
</item>
<item android:drawable="@android:drawable/btn_default"></item>
</selector>
Основное направление деятельности:
package com.example.buttontest;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
ColoredButton btnRed;
ColoredButton btnGreen;
Button btnSwitch;
boolean switched = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initButtons();
}
private void initButtons() {
btnRed = (ColoredButton) findViewById(R.id.btnRed);
btnGreen = (ColoredButton) findViewById(R.id.btnGreen);
btnRed.setIsRed(true);
btnGreen.setIsRed(false);
btnSwitch = (Button) findViewById(R.id.btnSwitch);
btnSwitch.setOnClickListener(this);
}
@Override
public void onClick(View v) {
btnRed.setIsRed(switched);
btnGreen.setIsRed(!switched);
switched = !switched;
}
}
Попробуйте код и посмотрите, хотите ли вы этого.
У меня есть несколько проблем с дизайном, которые вы пытаетесь достичь. Во-первых, зачем создавать класс RedButton, в котором четко указано, что это красная кнопка, а затем разрешать ему не только быть красным, но и зеленым? Почему бы не иметь RedButton и GreenButton? Гораздо меньше путаницы и более четкая цель.
Во-вторых, селекторы работают от состояний кнопок, определенных платформой Android. Вы не можете ввести свой собственный тип и ожидать, что он будет знать, о чем вы говорите. Вы, конечно, можете установить соответствующий цвет фона в своем собственном конструкторе Button, а также соответствующим образом изменить его в своем установщике, но я советую против этого.