所以我有一个警报列表,我将它绑定到listview,lstAlarms。在我的自定义ListView布局中,我还有一个开关,我想根据警报的状态以编程方式设置。我想在刚刚显示ListView后立即执行此操作。
请参阅下面的代码。 显示ListView的方法是DisplayAlarmList()。 我试图用来设置开关状态的方法是InitSwitches(),它在DisplayAlarmList()内部被调用。 在onCreate()方法中调用DisplayAlarmList()。
public void DisplayAlarmList()
{
final String[] columns = {Database.getAlarmID(), Database.getAlarmTime(), Database.getAlarmName(), Database.getAlarmStatus(), Database.getAlarmRepeats()};
Cursor c = Database.selectAlarm(db, Database.getTableName(), columns, null, null, null, null, null);
int[] to = new int[]{
R.id.alarmID,
R.id.alarmTime,
R.id.alarmName,
R.id.alarmStatus,
R.id.alarmRepeats,
};
SimpleCursorAdapter ca = new SimpleCursorAdapter(this,
R.layout.alarm_info,
c,
columns,
to,
0);
lstAlarm.setAdapter(ca);
InitSwitches();
lstAlarm.setOnItemClickListener(new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> listView, View view, int position, long id)
{
Alarm alarm = new Alarm();
Cursor selectedCursor = (Cursor) listView.getItemAtPosition(position);
Switch s = (Switch) view.findViewById(R.id.alarmSwitch);
String whereArgs = Integer.toString(selectedCursor.getInt(selectedCursor.getColumnIndexOrThrow(Database.getAlarmID())));
Cursor data = Database.RawQuery(db, "SELECT * FROM " + Database.getTableName() + " WHERE " + Database.getAlarmID() + " = " + whereArgs);
if (data.moveToFirst())
{
alarm.setAlarmID(data.getString(data.getColumnIndexOrThrow(Database.getAlarmID())));
alarm.setAlarmName(data.getString(data.getColumnIndexOrThrow(Database.getAlarmName())));
alarm.setAlarmTime(data.getString(data.getColumnIndexOrThrow(Database.getAlarmTime())));
alarm.setAlarmSound(data.getString(data.getColumnIndexOrThrow(Database.getAlarmSound())));
alarm.setAlarmRepeats(data.getString(data.getColumnIndexOrThrow(Database.getAlarmRepeats())));
alarm.setAlarmStatus(data.getString(data.getColumnIndexOrThrow(Database.getAlarmStatus())));
}
Intent i = new Intent(view.getContext(), ScreenEdit.class);
i.putExtra("editAlarm", new Gson().toJson(alarm));
startActivityForResult(i, EDIT_ALARM);
}
});
}
public void InitSwitches()
{
View v;
Switch s;
int index = 0;
String query = "Select " + Database.getAlarmID() + ", " + Database.getAlarmStatus() + " FROM " + Database.getTableName();
Cursor statuses = Database.RawQuery(db, query);
while (statuses.moveToNext())
{
v = lstAlarm.getAdapter().getView(index++, null, null);
s = (Switch) v.findViewById(R.id.alarmSwitch);
if (statuses.getString(statuses.getColumnIndexOrThrow(Database.getAlarmStatus())).equals("ON")){
s.toggle();
}
else{
}
}
}
从屏幕截图中可以看出,第二行中的开关应该是ON,但它不是。我也尝试了InvilidateView(),但没有工作。请帮忙。
答案 0 :(得分:3)
问题是ListView是不断重绘的那些视图之一,这意味着这很糟糕,因为它会在重绘时失去状态
if (statuses.getString(statuses.getColumnIndexOrThrow(Database.getAlarmStatus())).equals("ON")){
s.toggle();
}
首先创建 AlarmItem ...您应该根据自己的需要制作它。这是我的
public class AlarmItem {
private String alarmName;
private String alarmDescption;
private boolean state;
private long id;
public AlarmItem(String alarmName, String alarmDescption, long id, boolean state) {
this.alarmName = alarmName;
this.alarmDescption = alarmDescption;
this.id = id;
this.state = state;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAlarmName() {
return alarmName;
}
public void setAlarmName(String alarmName) {
this.alarmName = alarmName;
}
public String getAlarmDescption() {
return alarmDescption;
}
public void setAlarmDescption(String alarmDescption) {
this.alarmDescption = alarmDescption;
}
public boolean getState() {
return state;
}
public void setState(boolean state) {
this.state = state;
}
}
现在我们需要一个 CustomSwitch 类,因为:LINK
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Switch;
public class CustomSwitch extends Switch {
private OnCheckedChangeListener mListener;
public CustomSwitch(Context context) {
super(context);
}
public CustomSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
// Do not call supper method
mListener = listener;
}
@Override
public void setChecked(boolean checked) {
super.setChecked(checked);
if (mListener != null) {
mListener.onCheckedChanged(this, checked);
}
}
public void setCheckedProgrammatically(boolean checked) {
// You can call super method, it doesn't have a listener... he he :)
super.setChecked(checked);
}
}
创建一个布局文件并将其命名为 alarm_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="vertical">
<com.example.alarm.list.CustomSwitch
android:id="@+id/alarmSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_toLeftOf="@id/alarmSwitch"
android:orientation="vertical">
<TextView
android:id="@+id/tvAlarmName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="Alarm Name"
android:textSize="18sp"/>
<TextView
android:id="@+id/tvAlarmDesc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="Alarm description"
android:textSize="15sp"/>
</LinearLayout>
</RelativeLayout>
现在主要布局 - &gt;的 activity_main.xml中强>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/lvAlarms"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
现在我们需要一个负责绘制物品及其处理的适配器。将类命名为 AlarmAdapter
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CompoundButton;
import android.widget.TextView;
import java.util.List;
public class AlarmAdapter extends BaseAdapter {
private List<AlarmItem> listOfAlarms;
private Context context;
private OnAlarmCheckedChangeListener mCallback;
// avoid constant allocation
private View tmpView;
private AlarmItemViewHolder mHolder;
private AlarmItem tmpItem;
public AlarmAdapter(List<AlarmItem> listOfAlarms, Context context, OnAlarmCheckedChangeListener callBack) {
this.listOfAlarms = listOfAlarms;
this.context = context;
mCallback = callBack;
}
@Override
public int getCount() {
return listOfAlarms == null ? 0 : listOfAlarms.size();
}
@Override
public AlarmItem getItem(int i) {
return listOfAlarms == null ? null : listOfAlarms.get(i);
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(final int i, View view, ViewGroup viewGroup) {
tmpItem = listOfAlarms.get(i);
if (view == null) {
LayoutInflater inflater = LayoutInflater.from(context);
tmpView = inflater.inflate(R.layout.alarm_list_item, null, false);
mHolder = new AlarmItemViewHolder(tmpView);
tmpView.setTag(mHolder);
}
else {
tmpView = view;
mHolder = (AlarmItemViewHolder) view.getTag();
}
mHolder.getAlarmNameTextView().setText(tmpItem.getAlarmName());
mHolder.getAlarmDescriptionTextView().setText(tmpItem.getAlarmDescption());
mHolder.getSwitch().setCheckedProgrammatically(tmpItem.getState());
mHolder.getSwitch().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
listOfAlarms.get(i).setState(b);
mCallback.onAlarmStateChanged(listOfAlarms.get(i), i);
}
});
return tmpView;
}
public void clear() {
listOfAlarms.clear();
notifyDataSetChanged();
}
public void refill(List<AlarmItem> listOfAlarms) {
this.listOfAlarms = listOfAlarms;
notifyDataSetChanged();
}
public void toggleAllSwitches() {
for (AlarmItem item : listOfAlarms) {
item.setState(!item.getState());
}
notifyDataSetChanged();
}
public interface OnAlarmCheckedChangeListener {
public void onAlarmStateChanged(AlarmItem item, int postionInList);
}
private class AlarmItemViewHolder {
View base;
CustomSwitch mSwitch;
TextView mAlarmName;
TextView mAlarmDescription;
public AlarmItemViewHolder(View base) {
this.base = base;
}
public CustomSwitch getSwitch() {
if (mSwitch == null) {
mSwitch = (CustomSwitch) base.findViewById(R.id.alarmSwitch);
}
return mSwitch;
}
public TextView getAlarmNameTextView() {
if (mAlarmName == null) {
mAlarmName = (TextView) base.findViewById(R.id.tvAlarmName);
}
return mAlarmName;
}
public TextView getAlarmDescriptionTextView() {
if (mAlarmDescription == null) {
mAlarmDescription = (TextView) base.findViewById(R.id.tvAlarmDesc);
}
return mAlarmDescription;
}
}
}
现在终于 MainActivity
了import android.app.ActionBar;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends ActionBarActivity implements AdapterView.OnItemClickListener, AlarmAdapter.OnAlarmCheckedChangeListener {
private ListView listView;
private AlarmAdapter adapter;
private Toast toast;
private Handler handler;
private Runnable handlerRunnable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Make a nice actionBar title
ActionBar ab = getActionBar();
if (ab != null) {
ab.setTitle("Alarm List");
}
listView = (ListView) findViewById(R.id.lvAlarms);
// Simulating alarms from database. You need to convert your items to these
List<AlarmItem> alarmsFromDb = new ArrayList<>();
alarmsFromDb.add(new AlarmItem("Alarm 1", "Lalalala", 1, true));
alarmsFromDb.add(new AlarmItem("Alarm 2", "something", 2, false));
alarmsFromDb.add(new AlarmItem("Alarm 3", "gfdgdf", 3, true));
alarmsFromDb.add(new AlarmItem("Alarm 4", "sda", 4, true));
alarmsFromDb.add(new AlarmItem("Alarm 5", "yxcxyc", 5, false));
alarmsFromDb.add(new AlarmItem("Alarm 6", "dsfsd", 6, false));
adapter = new AlarmAdapter(alarmsFromDb, this, this);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
// Toggle all switches after 5s... this is what you need, right?
handlerRunnable = new Runnable() {
@Override
public void run() {
adapter.toggleAllSwitches();
showToast("All switches toggeled :)");
}
};
handler = new Handler(Looper.getMainLooper());
handler.postDelayed(handlerRunnable, 5 * 1000);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (handler != null) {
handler.removeCallbacks(handlerRunnable);
handler = null;
handlerRunnable = null;
}
}
private void showToast(String str) {
if (toast != null) {
toast.cancel();
}
toast = Toast.makeText(this, str, Toast.LENGTH_SHORT);
toast.show();
}
@Override
public void onAlarmStateChanged(AlarmItem item, int postionInList) {
String onOff = item.getState() ? "ON" : "OFF";
showToast("Alarm " + item.getAlarmName() + " is: " + onOff);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
AlarmItem item = adapter.getItem(position);
showToast("Alarm " + item.getAlarmName() + " clicked");
}
}
如果您遇到任何问题,这是完整的Android工作室项目:LINK
现在您需要做的就是将数据库中的结果转换为此列表,或修改 AlarmItem 和UI。此解决方案将起作用,您已在适配器中使用了一些有用的方法。
快乐的编码!
答案 1 :(得分:0)
你的适配器是否使用了视图模式?如果没有,那么关闭屏幕的视图将被重用,并且可能具有旧的切换状态,滚动时新行将不会出现。