【问题标题】:Spannable String only working for last Item in ListViewSpannable String 仅适用于 ListView 中的最后一项
【发布时间】:2017-02-16 23:49:47
【问题描述】:

编辑:

我现在可以在列表视图中敲击单词,但只能从底部向上敲击,之后只能取消敲击底部的项目。代码如下。

@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 的任何帮助。

【问题讨论】:

    标签: android listview layout textview spannablestring


    【解决方案1】:

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

    【讨论】:

    • 啊谢谢!!我现在就去那里。谢谢谢尔盖。
    • 所以我也尝试将这两个传递到函数中,除非我做错了,否则似乎已经完成了一半。如果我从下往上开始,我只能让所有项目的文本都被删除。但那之后我只能触底吗?我将编辑上面的代码。
    【解决方案2】:

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

    在这里制作了一个完整的示例:

    在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 应该能够并且需要从数据列表中获取数据。最简单的方法可能是:“getView() 中的 View.setTag(position),OnClickListener() 中的 View.getTag()”。
    4. 不要只修改视图。更改数据,先列出数据。然后调用 notifyDataSetChanged()。如果只是对 UI 进行小改动,可以直接做,但应该和调用 notifyDataSetChanged() 一样。

    希望有所帮助!

    【讨论】:

    • 非常感谢您的意见!我还没有机会解决它,但我会试一试,然后回复你。谢谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-23
    • 1970-01-01
    相关资源
    最近更新 更多