试图以编程方式设置一个ListView内开关的状态显示在列表视图后, [英] Trying to programmatically set the state of a SWITCH inside a LISTVIEW after the listview is displayed

查看:310
本文介绍了试图以编程方式设置一个ListView内开关的状态显示在列表视图后,的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我有报警的列表,我将绑定到ListView,lstAlarms。在我的自定义的ListView的布局,我也有一个开关,我想设置编程根据报警的状态。我想这样做的权利仅仅是显示在ListView后。

So i have a list of alarms and i bind that to the listview, lstAlarms. In my custom ListView layout, i also have a switch, which i want to be set programmatically according to the status of the alarm. I want to do this right after the ListView is just displayed.

请看看我的codeS下面。 这显示ListView控件的方法是DisplayAlarmList()。 ,即时通讯试图用设置开关的状态的方法是InitSwitches(),这是被称为DisplayAlarmList内()。 DisplayAlarmList()被调用在OnCreate()方法。

Please see my codes below. The method that display the ListView is DisplayAlarmList(). The method that im trying to use to set the states of the switches is InitSwitches(), which is being called inside of DisplayAlarmList(). DisplayAlarmList() is called in the onCreate() method.

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{                

        }
    }
}

应用截图

正如你从截图中看到,第二行中的开关应该是对的,但事实并非如此。我试过InvilidateView()太多,但没有工作。请大家帮帮忙。

As you can see from the screen shot, the switch in the second row is supposed to be ON, but it's not. I tried InvilidateView() too but didnt work. Please help.

推荐答案

问题是,ListView的是那些正在不断重绘的景色之一,这意味着这是不好的,监守重绘的时候就会失去状态。

The problem is that ListView is one of those views that is being constantly redrawn, meaning that this is bad, becuase it will lose the state when redrawn

if (statuses.getString(statuses.getColumnIndexOrThrow(Database.getAlarmStatus())).equals("ON")){
    s.toggle();
}

首先,创建 AlarmItem ...你应该根据你的需要做出来。这里是我的

First create AlarmItem... you should make it according to your needs. Here is mine

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 因为这个类:<一href="http://stackoverflow.com/questions/27310164/how-to-on-off-compount-button-programmatically-without-affecting-the-oncheckedch">LINK

Now we will need a CustomSwitch class because of this: 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>

现在主要布局 - > activity_main.xml

Now the main layout -> 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

Now we need an adapter that is responsible for drawing the items and their handling. Name the class 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");
    }
}

下面是完整的机器人工作室的项目,如果您有任何问题: LINK

Here is the complete android studio project, if you have any problems: LINK

现在你需要做的是从你的数据库中的结果转换到这个列表或修改 AlarmItem 和用户界面。该解决方案将工作,你已经有一些有用的方法,在适配器。

Now all you need to do is convert the results from your database to this list or modify the AlarmItem and the UI. This solution will work and you already have some helpful methods in the adapter.

编程快乐!

这篇关于试图以编程方式设置一个ListView内开关的状态显示在列表视图后,的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆