在自定义列表适配器中onClick on TextView时出现问题

时间:2014-07-27 07:14:08

标签: android listview android-listview

我编写了一个自定义适配器来加载ListView的列表。有用。目前,我有兴趣让它回复点击,以便发送电子邮件。我添加了代码以向我的点击监听器发送电子邮件(如this)。

这是来自我的自定义适配器;传递给构造函数MessagesAdapter()的上下文是getApplicationContext()。 (我按照建议here尝试使用this;但是,它没有用。)

public MessagesAdapter(Context context, int textViewResourceId, ArrayList<String> fileRecords) {
    super(context, textViewResourceId, fileRecords);
    this.ctx = context;
    this.l = fileRecords;
}

@SuppressLint("ViewHolder")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) ctx
    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.activity_messages_item, parent, false);

TextView hView = (TextView) rowView.findViewById(R.id.messageHeader);
TextView dView = (TextView) rowView.findViewById(R.id.messageDetail);
TextView fView = (TextView) rowView.findViewById(R.id.messageFooter);

String s = l.get(position);
String[] parts = s.split(";");

hView.setText(parts[0]);
rm.setmHeader(parts[0]);
hView.setTextSize(TypedValue.COMPLEX_UNIT_SP, ctx.getResources().getDimension(R.dimen.header_text));

dView.setText(parts[1]);
rm.setmDetail(parts[1]);
hView.setTextSize(TypedValue.COMPLEX_UNIT_SP, ctx.getResources().getDimension(R.dimen.detail_text));

fView.setText(parts[2]);
rm.setmFooter(parts[2]);
hView.setTextSize(TypedValue.COMPLEX_UNIT_SP, ctx.getResources().getDimension(R.dimen.footer_text));

dView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent intent = new Intent(Intent.ACTION_SEND);
            intent.setType("text/plain"); 
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra(Intent.EXTRA_EMAIL, rm.getmDetail().split(" ")[1]);
            intent.putExtra(Intent.EXTRA_SUBJECT, ctx.getResources().getString(R.string.email_subject) + " " + rm.getmHeader());
            ctx.startActivity(Intent.createChooser(intent, ""));
        }
    });

    return rowView;
}

我的问题似乎是startActivity()造成的。如果不使用ctx.startActivity(),我会得到一个空指针异常。如果我这样做,我会得到Android运行时异常。即使使用Intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

也是如此
07-27 02:50:15.747: E/AndroidRuntime(2092): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

所以,在这里。

  1. 活动会将MessageAdapter设置为ListView
  2. 适配器正确设置带有列表数据的文本视图。
  3. 适配器还会设置View.OnClickListener()
  4. 单击显示的消息时,应用程序崩溃。

    您能帮我解决一下如何实施点击吗?

    各个项目的布局

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    tools:context="com.foo.bar.MessageActivity" >
    
    <TextView
        android:id="@+id/messageHeader"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:textStyle="bold"/>
    
    <TextView
        android:id="@+id/messageDetail"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/messageHeader"
        android:autoLink="email"/>
    
    <TextView
        android:id="@+id/messageFooter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/messageDetail" />
    
    </RelativeLayout>
    

    列表视图的布局:

    <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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.foo.bar.MessagesActivity" >
    <ListView
        android:id="@android:id/list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:layout_alignParentLeft="true" >
    </ListView>
    
    </RelativeLayout>
    

    邮件适配器代码

    import java.util.ArrayList;
    
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.util.TypedValue;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.TextView;
    
    public class MessagesAdapter extends ArrayAdapter<String> {
        private Context ctx;
        private ArrayList<String> l;
        ReceivedMessages rm = new ReceivedMessages();
    
        public MessagesAdapter(Context context, int textViewResourceId, ArrayList<String> fileRecords) {
            super(context, textViewResourceId, fileRecords);
            this.ctx = context;
            this.l = fileRecords;
        }
    
        @SuppressLint("ViewHolder")
        @Override
          public View getView(int position, View convertView, ViewGroup parent) {
            LayoutInflater inflater = (LayoutInflater) ctx
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View rowView = inflater.inflate(R.layout.activity_messages_item, parent, false);
    
            TextView hView = (TextView) rowView.findViewById(R.id.messageHeader);
            TextView dView = (TextView) rowView.findViewById(R.id.messageDetail);
            TextView fView = (TextView) rowView.findViewById(R.id.messageFooter);
    
            String s = l.get(position);
            String[] parts = s.split(";");
    
            hView.setText(parts[0]);
            hView.setTextSize(TypedValue.COMPLEX_UNIT_SP, ctx.getResources().getDimension(R.dimen.header_text));
            hView.setClickable(false);
            hView.setLongClickable(false);
            hView.setOnClickListener(null);
    
            dView.setText(parts[1]);
            dView.setTextSize(TypedValue.COMPLEX_UNIT_SP, ctx.getResources().getDimension(R.dimen.detail_text));
            dView.setClickable(false);
            dView.setLongClickable(false);
    
            fView.setText(parts[2]);
            fView.setTextSize(TypedValue.COMPLEX_UNIT_SP, ctx.getResources().getDimension(R.dimen.footer_text));
            fView.setClickable(false);
            dView.setOnClickListener(null);
    
            return rowView;
        }
    }
    

    使用MessageAdapter

    // Handler for received Intents
    private BroadcastReceiver fileReadReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            populateList();
        }
    };
    
    
    private void populateList() {
        String[] values = fc.getMessageArray();
        final ArrayList<String> list = new ArrayList<String>();
        for (int i = 0; i < values.length; i++) {
            list.add(values[values.length-1-i]);   // Reversing the list to show recent messages first
            ++i;
        }
    
        MessagesAdapter ma = new MessagesAdapter(getApplicationContext(),
                R.layout.activity_messages_item, list);
        final ListView listView = (ListView) findViewById(android.R.id.list);
        listView.setClickable(true);
        listView.setAdapter(ma);
    
        listView.setOnItemClickListener(new ListView.OnItemClickListener() {
    
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                String s = list.get(Long.valueOf(id).intValue());
                Log.d("MessagesActivity", s);
    
                Intent emailintent = new Intent(android.content.Intent.ACTION_SEND);
                emailintent.setType("plain/text");
                emailintent.putExtra(android.content.Intent.EXTRA_EMAIL,new String[] {"random@gmail.com" });
                emailintent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
                emailintent.putExtra(android.content.Intent.EXTRA_TEXT,"");
            }
    
        }) ;
    }
    

2 个答案:

答案 0 :(得分:4)

您还可以使用android.text.SpannableStringandroid.text.style.URLSpan创建可点击的文字。您还可以使用不同的操作在同一TextView中单击或单击文本的一部分。我为你做了这个例子:

MainActivity:

    public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getFragmentManager().beginTransaction().add(R.id.container, new MainFragment()).commit();

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

MainFragment:

    public class MainFragment extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View view = inflater.inflate(R.layout.fragment_main, null);
        ListView list = (ListView)view.findViewById(R.id.listView1);
        ArrayList<String> items = new ArrayList<String>();

        for(int i = 0; i < 10; i++){
            items.add("These both words are clickable: word1 word2");
        }

        ListAdapter adapter = new ListAdapter(getActivity(), items);
        list.setAdapter(adapter);
        return view;
    }

    private class ListAdapter extends BaseAdapter {
        private LayoutInflater mInflater;
        private ArrayList<String> mListItems;

        public ListAdapter(Context context, ArrayList<String> items){
            mInflater = LayoutInflater.from(context);
            mListItems = items;
        }

        @Override
        public int getCount() {
            return mListItems.size();
        }

        @Override
        public Object getItem(int position) {
            return mListItems.get(position);
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        public Spannable setSpan(String text){
            Spannable span = new SpannableString(text);
            //Span the word that you want to be clickable, in this case we span two words 
            //These both words are clickable: word1 word2
            //Span word1, this will also underline the word
            span.setSpan(new SpanListener(text.substring(32, 37)), 32, 37, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            span.setSpan(new SpanListener(text.substring(38, 43)), 38, 43, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

            return span;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if(convertView == null){
                holder = new ViewHolder();
                convertView = mInflater.inflate(R.layout.list_item, null);

                holder.text = (TextView)convertView.findViewById(R.id.textView1);
                convertView.setTag(holder);

            } else{
                holder = (ViewHolder)convertView.getTag();
            }

            holder.text.setText(setSpan(mListItems.get(position)));
            holder.text.setMovementMethod(LinkMovementMethod.getInstance());

            ((ViewGroup)convertView).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
            return convertView;
        }



    }

    static class ViewHolder {
        TextView text;
    }

    public class SpanListener extends URLSpan {
        String spanned_text;

        public SpanListener(String text) {
            super(text);
            spanned_text = text;
        }

        public void onClick(View v){
            DialogFragment dialog = new TextDialog();
            Bundle bundle = new Bundle();

            bundle.putString("text", spanned_text);
            dialog.setArguments(bundle);
            dialog.show(getFragmentManager(), "");
        }

        @Override 
        public void updateDrawState(TextPaint paint) {
            super.updateDrawState(paint);
            //Remove underline
            paint.setUnderlineText(false);
        }

    }

    public static class TextDialog extends DialogFragment implements OnClickListener {

        @Override
        public Dialog onCreateDialog(Bundle savedinstanceState){
            final Context context = this.getActivity();
            String text = "";
            Bundle bundle = this.getArguments();
            if(bundle != null){
                text = bundle.getString("text");
            }

            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setMessage("You clicked: " + text);
            builder.setPositiveButton("OK", this);
            return builder.create();
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {
            // TODO Auto-generated method stub

        }
    }

}

list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="10dp" />

fragment_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="com.example.clickabletextviewinsidelistview.MainActivity$PlaceholderFragment" >

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

结果:

答案 1 :(得分:0)

此问题的罪魁祸首可能是android:autoLink="email"android:layout_width="match_parent"。这会使用一个可点击的TextView填充ListView的项目。

此外,您似乎将其设置为无法点击,因此最终挖掘自己一个洞: - )

如果ListView的整个项目都是可点击的,则无需使用autoLink标记。所以只需删除它。其他一切似乎都很好。希望这适用于你。快乐的编码! : - )