Thanks Jack,

Constraining the problem to a TextView rather than the whole row view
is a good idea, but the apparent cast problem has now moved to
holder.text = (MyUnderlinedTextView) convertView.findViewById
(R.id.text);  And, changing the definition of the ViewHolder from

        static class ViewHolder {
            TextView text;
            ImageView icon;
        }

to

        static class ViewHolder {
            MyUnderlinedTextView text;
            ImageView icon;
        }

did not get rid of the apparent cast problem.  Here's the current code
and stack trace.  This evening I'll try changing the row's layout so
it references a MyUnderlinedTextView rather than a TextView.  However
I was hoping that the seemingly simple addition of underlining
wouldn't require modification to the layout.

- - -

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.apis.view;

import android.app.ListActivity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * Demonstrates how to write an efficient list adapter. The adapter
used in this example binds
 * to an ImageView and to a TextView for each row in the list.
 *
 * To work efficiently the adapter implemented here uses two
techniques:
 * - It reuses the convertView passed to getView() to avoid inflating
View when it is not necessary
 * - It uses the ViewHolder pattern to avoid calling findViewById()
when it is not necessary
 *
 * The ViewHolder pattern consists in storing a data structure in the
tag of the view returned by
 * getView(). This data structures contains references to the views we
want to bind data to, thus
 * avoiding calls to findViewById() every time getView() is invoked.
 */
public class List14 extends ListActivity {

        private static class MyUnderlinedTextView extends TextView {
                public MyUnderlinedTextView(Context context) {
                        super(context);
                }
                public MyUnderlinedTextView(Context context, AttributeSet as) {
                        super(context, as);
                }
                public MyUnderlinedTextView(Context context, AttributeSet as, 
int i)
{
                        super(context, as, i);
                }
            @Override
            protected void onDraw(Canvas canvas){
                super.onDraw(canvas);

                // Would like to do some line drawing here (e.g., underlining
portions of text)
            }
        }

    private static class EfficientAdapter extends BaseAdapter {
        private LayoutInflater mInflater;
        private Bitmap mIcon1;
        private Bitmap mIcon2;

        public EfficientAdapter(Context context) {
            // Cache the LayoutInflate to avoid asking for a new one
each time.
            mInflater = LayoutInflater.from(context);

            // Icons bound to the rows.
            mIcon1 = BitmapFactory.decodeResource(context.getResources
(), R.drawable.icon48x48_1);
            mIcon2 = BitmapFactory.decodeResource(context.getResources
(), R.drawable.icon48x48_2);
        }

        /**
         * The number of items in the list is determined by the number
of speeches
         * in our array.
         *
         * @see android.widget.ListAdapter#getCount()
         */
        public int getCount() {
            return DATA.length;
        }

        /**
         * Since the data comes from an array, just returning the
index is
         * sufficent to get at the data. If we were using a more
complex data
         * structure, we would return whatever object represents one
row in the
         * list.
         *
         * @see android.widget.ListAdapter#getItem(int)
         */
        public Object getItem(int position) {
            return position;
        }

        /**
         * Use the array index as a unique id.
         *
         * @see android.widget.ListAdapter#getItemId(int)
         */
        public long getItemId(int position) {
            return position;
        }

        /**
         * Make a view to hold each row.
         *
         * @see android.widget.ListAdapter#getView(int,
android.view.View,
         *      android.view.ViewGroup)
         */
        public View getView(int position, View convertView, ViewGroup
parent) {
            // A ViewHolder keeps references to children views to
avoid unneccessary calls
            // to findViewById() on each row.
            ViewHolder holder;

            // When convertView is not null, we can reuse it directly,
there is no need
            // to reinflate it. We only inflate a new View when the
convertView supplied
            // by ListView is null.
            if (convertView == null) {
                convertView = mInflater.inflate
(R.layout.list_item_icon_text, null);

                // Creates a ViewHolder and store references to the
two children views
                // we want to bind data to.
                holder = new ViewHolder();
                holder.text = (MyUnderlinedTextView)
convertView.findViewById(R.id.text);
                holder.icon = (ImageView) convertView.findViewById
(R.id.icon);

                convertView.setTag(holder);
            } else {
                // Get the ViewHolder back to get fast access to the
TextView
                // and the ImageView.
                holder = (ViewHolder) convertView.getTag();
            }

            // Bind the data efficiently with the holder.
            holder.text.setText(DATA[position]);
            holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 :
mIcon2);

            return convertView;
        }

        static class ViewHolder {
            MyUnderlinedTextView text;
            ImageView icon;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setListAdapter(new EfficientAdapter(this));
    }

    private static final String[] DATA = {
            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam",
            "Abondance", "Ackawi", "Acorn", "Adelost", "Affidelice au
Chablis",
            "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
           " ... ",
           "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"};
}

- - -

D/AndroidRuntime(  721): Shutting down VM

W/dalvikvm(  721): threadid=3: thread exiting with uncaught exception
(group=0x4000fe70)

E/AndroidRuntime(  721): Uncaught handler: thread main exiting due to
uncaught exception

E/AndroidRuntime(  721): java.lang.ClassCastException:
android.widget.TextView

E/AndroidRuntime(  721):        at
com.example.android.apis.view.List14$EfficientAdapter.getView
(List14.java:130)

E/AndroidRuntime(  721):        at android.widget.AbsListView.obtainView
(AbsListView.java:1269)

E/AndroidRuntime(  721):        at android.widget.ListView.makeAndAddView
(ListView.java:1623)

E/AndroidRuntime(  721):        at android.widget.ListView.fillDown
(ListView.java:607)

E/AndroidRuntime(  721):        at android.widget.ListView.fillFromTop
(ListView.java:664)

E/AndroidRuntime(  721):        at android.widget.ListView.layoutChildren
(ListView.java:1481)

E/AndroidRuntime(  721):        at android.widget.AbsListView.onLayout
(AbsListView.java:1113)

E/AndroidRuntime(  721):        at android.view.View.layout(View.java:6133)

E/AndroidRuntime(  721):        at android.widget.FrameLayout.onLayout
(FrameLayout.java:333)

E/AndroidRuntime(  721):        at android.view.View.layout(View.java:6133)

E/AndroidRuntime(  721):        at android.widget.LinearLayout.setChildFrame
(LinearLayout.java:1119)

E/AndroidRuntime(  721):        at android.widget.LinearLayout.layoutVertical
(LinearLayout.java:998)

E/AndroidRuntime(  721):        at android.widget.LinearLayout.onLayout
(LinearLayout.java:918)

E/AndroidRuntime(  721):        at android.view.View.layout(View.java:6133)

E/AndroidRuntime(  721):        at android.widget.FrameLayout.onLayout
(FrameLayout.java:333)

E/AndroidRuntime(  721):        at android.view.View.layout(View.java:6133)

E/AndroidRuntime(  721):        at android.view.ViewRoot.performTraversals
(ViewRoot.java:929)

E/AndroidRuntime(  721):        at android.view.ViewRoot.handleMessage
(ViewRoot.java:1482)

E/AndroidRuntime(  721):        at android.os.Handler.dispatchMessage
(Handler.java:99)

E/AndroidRuntime(  721):        at android.os.Looper.loop(Looper.java:123)

E/AndroidRuntime(  721):        at android.app.ActivityThread.main
(ActivityThread.java:3948)

E/AndroidRuntime(  721):        at java.lang.reflect.Method.invokeNative
(Native Method)

E/AndroidRuntime(  721):        at java.lang.reflect.Method.invoke
(Method.java:521)

E/AndroidRuntime(  721):        at com.android.internal.os.ZygoteInit
$MethodAndArgsCaller.run(ZygoteInit.java:782)

E/AndroidRuntime(  721):        at com.android.internal.os.ZygoteInit.main
(ZygoteInit.java:540)

E/AndroidRuntime(  721):        at dalvik.system.NativeStart.main(Native
Method)

I/Process (  564): Sending signal. PID: 721 SIG: 3

- - -

Thanks again and best regards,
Greg


On Jul 29, 11:55 am, Jack Ha <[email protected]> wrote:
> Don't do this:
>
>     UnderlinedView underlinedView = (UnderlinedView) convertView;
>
> Instead create your own MyUnderlinedTextView class by extending
> TextView.
>
>     holder.text = (MyUnderlinedTextView) convertView.findViewById
> (R.id.text);
>
> --
> Jack Ha
> Open Source Development Center
> ・T・ ・ ・Mobile・ stick together
>
> The views, opinions and statements in this email are those of
> the author solely in their individual capacity, and do not
> necessarily represent those of T-Mobile USA, Inc.
>
> On Jul 28, 7:54 pm, greg <[email protected]> wrote:
>
> > When I try extending the View class to a subclass that will underline
> > portions of the text drawn byListView, the code compiles okay but
> > results in a runtime exception apparently due to an improper class
> > cast.  Does anyone see what I've done wrong or have suggestions about
> > getting access to theCanvasofListViewitems so portions of text can
> > be underlined?
>
> > Here is the code, which is the Efficient Adapter View/List example
> > from ApiDemos with an added UnderlinedView class.
>
> > - - -
>
> > /*
> >  * Copyright (C) 2008 The Android Open Source Project
> >  *
> >  * Licensed under the Apache License, Version 2.0 (the "License");
> >  * you may not use this file except in compliance with the License.
> >  * You may obtain a copy of the License at
> >  *
> >  *      http://www.apache.org/licenses/LICENSE-2.0
> >  *
> >  * Unless required by applicable law or agreed to in writing, software
> >  * distributed under the License is distributed on an "AS IS" BASIS,
> >  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> > implied.
> >  * See the License for the specific language governing permissions and
> >  * limitations under the License.
> >  */
>
> > package com.example.android.apis.view;
>
> > import android.app.ListActivity;
> > import android.content.Context;
> > import android.graphics.Bitmap;
> > import android.graphics.BitmapFactory;
> > import android.graphics.Canvas;
> > import android.os.Bundle;
> > import android.util.AttributeSet;
> > import android.view.LayoutInflater;
> > import android.view.View;
> > import android.view.ViewGroup;
> > import android.widget.BaseAdapter;
> > import android.widget.ImageView;
> > import android.widget.TextView;
>
> > /**
> >  * Demonstrates how to write an efficient list adapter. The adapter
> > used in this example binds
> >  * to an ImageView and to a TextView for each row in the list.
> >  *
> >  * To work efficiently the adapter implemented here uses two
> > techniques:
> >  * - It reuses the convertView passed to getView() to avoid inflating
> > View when it is not necessary
> >  * - It uses the ViewHolder pattern to avoid calling findViewById()
> > when it is not necessary
> >  *
> >  * The ViewHolder pattern consists in storing a data structure in the
> > tag of the view returned by
> >  * getView(). This data structures contains references to the views we
> > want to bind data to, thus
> >  * avoiding calls to findViewById() every time getView() is invoked.
> >  */
> > public class List14 extends ListActivity {
>
> >         private static class UnderlinedView extends View {
> >                 public UnderlinedView(Context context) {
> >                         super(context);
> >                 }
> >                 public UnderlinedView(Context context, AttributeSet as) {
> >                         super(context, as);
> >                 }
> >                 public UnderlinedView(Context context, AttributeSet as, int 
> > i) {
> >                         super(context, as, i);
> >                 }
> >             @Override
> >             protected void onDraw(Canvascanvas) {
> >                 super.onDraw(canvas);
>
> >                 // Would like to do some line drawing here (e.g., 
> > underlining
> > portions of text)
> >             }
> >         }
>
> >     private static class EfficientAdapter extends BaseAdapter {
> >         private LayoutInflater mInflater;
> >         private Bitmap mIcon1;
> >         private Bitmap mIcon2;
>
> >         public EfficientAdapter(Context context) {
> >             // Cache the LayoutInflate to avoid asking for a new one
> > each time.
> >             mInflater = LayoutInflater.from(context);
>
> >             // Icons bound to the rows.
> >             mIcon1 = BitmapFactory.decodeResource(context.getResources
> > (), R.drawable.icon48x48_1);
> >             mIcon2 = BitmapFactory.decodeResource(context.getResources
> > (), R.drawable.icon48x48_2);
> >         }
>
> >         /**
> >          * The number of items in the list is determined by the number
> > of speeches
> >          * in our array.
> >          *
> >          * @see android.widget.ListAdapter#getCount()
> >          */
> >         public int getCount() {
> >             return DATA.length;
> >         }
>
> >         /**
> >          * Since the data comes from an array, just returning the
> > index is
> >          * sufficent to get at the data. If we were using a more
> > complex data
> >          * structure, we would return whatever object represents one
> > row in the
> >          * list.
> >          *
> >          * @see android.widget.ListAdapter#getItem(int)
> >          */
> >         public Object getItem(int position) {
> >             return position;
> >         }
>
> >         /**
> >          * Use the array index as a unique id.
> >          *
> >          * @see android.widget.ListAdapter#getItemId(int)
> >          */
> >         public long getItemId(int position) {
> >             return position;
> >         }
>
> >         /**
> >          * Make a view to hold each row.
> >          *
> >          * @see android.widget.ListAdapter#getView(int,
> > android.view.View,
> >          *      android.view.ViewGroup)
> >          */
> >         public View getView(int position, View convertView, ViewGroup
> > parent) {
> >             // A ViewHolder keeps references to children views to
> > avoid unneccessary calls
> >             // to findViewById() on each row.
> >             ViewHolder holder;
> >             UnderlinedView underlinedView = (UnderlinedView)
> > convertView;
>
> >             // When convertView is not null, we can reuse it directly,
> > there is no need
> >             // to reinflate it. We only inflate a new View when the
> > convertView supplied
> >             // byListViewis null.
> >             if (convertView == null) {
> >                 convertView = mInflater.inflate
> > (R.layout.list_item_icon_text, null);
> >                 underlinedView = (UnderlinedView)convertView;
>
> >                 // Creates a ViewHolder and store references to the
> > two children views
> >                 // we want to bind data to.
> >                 holder = new ViewHolder();
> >                 holder.text = (TextView) underlinedView.findViewById
> > (R.id.text);
> >                 holder.icon = (ImageView) underlinedView.findViewById
> > (R.id.icon);
>
> >                 underlinedView.setTag(holder);
> >             } else {
> >                 // Get the ViewHolder back to get fast access to the
> > TextView
> >                 // and the ImageView.
> >                 holder = (ViewHolder) underlinedView.getTag();
> >             }
>
> >             // Bind the data efficiently with the holder.
> >             holder.text.setText(DATA[position]);
> >             holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 :
> > mIcon2);
>
> >             return underlinedView;
> >         }
>
> >         static class ViewHolder {
> >             TextView text;
> >             ImageView icon;
> >         }
> >     }
>
> >     @Override
> >     public void onCreate(Bundle savedInstanceState) {
> >         super.onCreate(savedInstanceState);
> >         setListAdapter(new EfficientAdapter(this));
> >     }
>
> >     private static final String[] DATA = {
> >             "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam",
> >             "Abondance", "Ackawi", "Acorn", "Adelost", "Affidelice au
> > Chablis",
> >             "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
> >             "... a lot more strings are defined in original ApiDemos
> > sample ...",
> >             "Yarra Valley Pyramid", "Yorkshire Blue", "Zamorano",
> >             "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"};
>
> > }
>
> > - - -
>
> > The stack trace from logcat suggests a problem with the class cast in
> > line 127, which is the cast after the row's XML inflation in getView:
>
> >                 convertView = mInflater.inflate
> > (R.layout.list_item_icon_text, null);
> >                 underlinedView = (UnderlinedView)convertView;
>
> > D/AndroidRuntime(  723): Shutting down VM
>
> > W/dalvikvm(  723): threadid=3: thread exiting with uncaught exception
> > (group=0x4000fe70)
>
> > E/AndroidRuntime(  723): Uncaught handler: thread main exiting due to
> > uncaught exception
>
> > E/AndroidRuntime(  723): java.lang.ClassCastException:
> > android.widget.LinearLayout
>
> > E/AndroidRuntime(  723):        at
> > com.example.android.apis.view.List14$EfficientAdapter.getView
> > (List14.java:127)
>
> > E/AndroidRuntime(  723):        at android.widget.AbsListView.obtainView
> > (AbsListView.java:1269)
>
> > E/AndroidRuntime(  723):        at android.widget.ListView.makeAndAddView
> > (ListView.java:1623)
>
> > E/AndroidRuntime(  723):        at android.widget.ListView.fillDown
> > (ListView.java:607)
>
> > E/AndroidRuntime(
>
> ...
>
> read more »
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to