Spannable String仅适用于ListView

时间:2016-10-07 21:59:47

标签: android listview layout textview spannablestring

编辑:

我现在能够在列表视图中查找单词,但只能从下到上执行此操作,之后只能对底部项目进行取消操作。代码如下。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final SubTask subTask = getItem(position);

    if(convertView == null){
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.subtask_adapter_list, parent, false);
    }

    final TextView tasksTitle = (TextView)convertView.findViewById(R.id.tasksName);
    tasksTitle.setTypeface(typeface);
    completed = (CheckBox)convertView.findViewById(R.id.completed);
    changeColor();

    tasksTitle.setText(subTask.getSubTask());

    completed.setChecked(subTask.isCompleted());

    toggleLineThrough(tasksTitle, tasksTitle.getText().toString(), subTask.getSubTask(), completed.isChecked());

    completed.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(completed.isChecked()){
                subTask.setCompleted(true);
                subTask.save();
                toggleLineThrough(tasksTitle, tasksTitle.getText().toString(), subTask.getSubTask(), completed.isChecked());
            } else {
                subTask.setCompleted(false);
                subTask.save();
                toggleLineThrough(tasksTitle, tasksTitle.getText().toString(), subTask.getSubTask(), completed.isChecked());
            }
        }
    });

    return convertView;
}

private void toggleLineThrough(TextView tasksTitle, String title, String oldTitle, boolean completed){
    SpannableString styledString = new SpannableString(title);
    if(completed == true){
        styledString.setSpan(new StrikethroughSpan(), 0, title.length(), 0);
        tasksTitle.setText(styledString);
    } else {
        tasksTitle.setText(oldTitle);
    }
}

如果符合条件,我正试图让罢工跨越TextView。逻辑上它可以工作,但仅适用于ListView中的最后一项。所有其他物品似乎根本不会产生罢工。我的代码如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    subTask = getItem(position);

    if(convertView == null){
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.subtask_adapter_list, parent, false);
    }

    tasksTitle = (TextView)convertView.findViewById(R.id.tasksName);
    tasksTitle.setTypeface(typeface);
    completed = (CheckBox)convertView.findViewById(R.id.completed);
    changeColor();

    tasksTitle.setText(subTask.getSubTask());

    toggleLineThrough(subTask.getSubTask());

    completed.setChecked(subTask.isCompleted());

    completed.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(completed.isChecked()){
                subTask.setCompleted(true);
                subTask.save();
                toggleLineThrough(subTask.getSubTask());
            } else {
                subTask.setCompleted(false);
                subTask.save();
                toggleLineThrough(subTask.getSubTask());
            }
        }
    });

    return convertView;
}

private void toggleLineThrough(String text){
    SpannableString styledString = new SpannableString(text);
    if(completed.isChecked()){
        styledString.setSpan(new StrikethroughSpan(), 0, text.length(), 0);
        tasksTitle.setText(styledString);
    } else {
        tasksTitle.setText(text);
    }
}

我似乎无法让罢工为他们所有人工作。我也试过使用Paint Flags方法得到相同的结果(甚至完全隐藏了我的TextView)。

将非常感谢在ListView中为TextViews使用Spannable String的任何帮助

2 个答案:

答案 0 :(得分:0)

您也应将已检查状态和tasksTitle传递给toggleLineThrough()。 变量completedtasksTitle包含错误的值,因为onClickListener的调用时间晚于getView()。他们被getView()的连续电话多次覆盖。

答案 1 :(得分:0)

@SmiffyKmc,我正在尝试使用以下内容来回答其他类似问题,因此某些评论可能与您的问题无关。

在这里完成了一个完整的样本:

在strings.xml中:

    <string-array name="list_items_sample">
    <item>One</item>
    <item>Two</item>
    <item>Three</item>
    <item>Four</item>
    <item>Five</item>
    <item>Six</item>
    <item>Seven</item>
    <item>Eight</item>
    <item>Nine</item>
    <item>Ten</item>
    <item>Eleven</item>
    <item>Twelve</item>
    <item>Thirteen</item>
    <item>Fourteen</item>
    <item>Fifteen</item>
    <item>Sixteen</item>
    <item>Seventeen</item>
    <item>Eighteen</item>
    <item>Nineteen</item>
    <item>Twenty</item>
</string-array>

activity_main.xml中:

<RelativeLayout 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"
tools:context="${relativePackage}.${activityClass}" >

<ListView
    android:id="@+id/listView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="7dp" >

</ListView>

custom_list_items.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/RelativeLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="20dp"
android:paddingTop="20dp" >

<CheckBox
    android:id="@+id/cb"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentEnd="true"
    android:layout_alignParentRight="true"
    android:focusable="false" />

<TextView
    android:id="@+id/tvId"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBaseline="@+id/cb"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_alignParentTop="true"
    android:layout_marginBottom="5dp"
    android:layout_marginTop="5dp"
    android:gravity="center"
    android:minWidth="70dp"
    android:textSize="25sp" />

<TextView
    android:id="@+id/tvDescription"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignBaseline="@+id/cb"
    android:layout_alignParentTop="true"
    android:layout_toEndOf="@id/tvId"
    android:layout_toLeftOf="@+id/cb"
    android:layout_toRightOf="@id/tvId"
    android:layout_toStartOf="@id/cb" />

MainActivity.java:

public class MainActivity extends Activity {
static final String ITEM_ID = "item_id";
static final String ITEM_NAME = "item_name";
static final String ITEM_CHECKED ="item_checked";
ListView mListView;

ArrayList<HashMap<String, Object>> mDataList = new ArrayList<>();
ArrayAdapter<HashMap<String, Object>> mArrayAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mListView = (ListView) findViewById(R.id.listView1);

    String items[] = getResources().getStringArray(R.array.list_items_sample);
    mDataList.clear();
    for(int i=1; i<20; i++){
        HashMap<String, Object> newItem = new HashMap<String, Object>();
        newItem.put(ITEM_ID, String.valueOf(i));
        newItem.put(ITEM_NAME, "Sample<"+items[i-1]+">");
        newItem.put(ITEM_CHECKED, false);
        mDataList.add(newItem);
    }

    mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

    mArrayAdapter = new ArrayAdapter<HashMap<String, Object>>(getApplicationContext(), R.layout.custom_list_items, mDataList){
        class ViewHolder{
            CheckBox cb;
            TextView tvId;
            TextView tvDescription;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            // Prepare views ready for data
            if(convertView == null){
                convertView = LayoutInflater.from(getContext()).inflate(R.layout.custom_list_items, parent, false);
                holder = new ViewHolder();
                holder.cb = (CheckBox) convertView.findViewById(R.id.cb);
                holder.tvId = (TextView) convertView.findViewById(R.id.tvId);
                holder.tvDescription = (TextView) convertView.findViewById(R.id.tvDescription);
                convertView.setTag(holder);

                holder.cb.setOnClickListener(new OnClickListener(){
                    @Override
                    public void onClick(View view) {
                        // Get view, position and DataList(position)
                        CheckBox buttonView = (CheckBox) view;
                        int pos = (int) buttonView.getTag();
                        HashMap<String, Object> selectedItem = new HashMap<String, Object>();
                        selectedItem = getItem(pos);

                        // Update DataList
                        remove(selectedItem);
                        selectedItem.remove(ITEM_CHECKED);
                        if(buttonView.isChecked()){
                            selectedItem.put(ITEM_CHECKED, true);
                            insert(selectedItem, pos);
                        }else{
                            selectedItem.put(ITEM_CHECKED, false);
                            insert(selectedItem, pos);
                        }

                        // Update all UI views by
                        notifyDataSetChanged();
                        // or Update the affected views directly
//                          View itemView = (View) buttonView.getParent();
//                          TextView tv = (TextView) itemView.findViewById(R.id.tvDescription);
//                          toggleLineThrough(tv, (String)getItem(pos).get(ITEM_NAME), buttonView.isChecked());
                    }
                });
            }else{
                holder = (ViewHolder) convertView.getTag();
            }

            // Get data from DataList
            HashMap<String, Object> currentItem = getItem(position);

            // Setup List items UI
            holder.tvId.setText((String)currentItem.get(ITEM_ID));
            holder.cb.setChecked((boolean)currentItem.get(ITEM_CHECKED));
            toggleLineThrough(holder.tvDescription, (String)currentItem.get(ITEM_NAME), (boolean)currentItem.get(ITEM_CHECKED));

            // Save position to CheckBox, so position can be retrieved when CheckBox is clicked
            holder.cb.setTag(position);

            return convertView;
        }
        private void toggleLineThrough(TextView tasksTitle, String title, boolean completed){
            SpannableString styledString = new SpannableString(title);
            if(completed == true){
                styledString.setSpan(new StrikethroughSpan(), 0, title.length(), 0);
                tasksTitle.setText(styledString);
            }else{
                tasksTitle.setText(title);
            }
        }
    };
    mListView.setAdapter(mArrayAdapter);
}
}

一些要点:

  1. 将CheckBox的状态保持为数据列表和设置UI中的字段,否则滚动后ListView将出错。
  2. getView()在显示ListView时结束。 OnClickListener不应该使用从getView()获得的数据。
  3. OnClickListener应该可以从数据列表中获取数据。最简单的方法可能是:&#34; getView()中的View.setTag(position),OnClickListener()中的View.getTag()&#34;。
  4. 不要仅修改视图。首先更改数据,数据列表。然后调用notifyDataSetChanged()。如果UI只有很小的变化,可以直接进行,但应该与调用notifyDataSetChanged()相同。
  5. 希望有所帮助!