Visa formatterad text i en Listview

Diskussion i 'Frågor, support och diskussion' startad av Sigma78, 28 dec 2010.

  1. Sigma78

    Sigma78 Teen Droid Medlem

    Blev medlem:
    27 jul 2010
    Inlägg:
    360
    Mottagna gillanden:
    6

    MINA ENHETER

    Jag har en ListView med tillhörande ArrayAdapter av typen WebObject, som är min egna interna klass.

    WebObject är väldigt enkel, den har bara två medlemmar, Spanned Text och String Link, som är text med tillhörande länk att följa när användaren klickar på den.

    För att få något att visas i min ListView fick jag implementera .toString, som konverterar Text från Spanned till String och returnerar den. Detta tar dessvärre bort all formattering på texten.

    Hur ska jag göra för att kunna få in min text i listan så som den är lagrad?

    Jag har försökt implementera getView, men utan att lyckas. Den anropas aldrig.
     
  2. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    I Snowstorm har jag en ListView som nog gör det du vill. Har inte tillgång till koden just nu, men skall försöka komma ihåg att kolla hur jag gjort när jag kommer hem ikväll.
     
  3. Sigma78

    Sigma78 Teen Droid Medlem

    Blev medlem:
    27 jul 2010
    Inlägg:
    360
    Mottagna gillanden:
    6

    MINA ENHETER

    Det hade varit kanon!

    Sent from my GT-I9000 using Tapatalk
     
  4. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    Hm, Vet inte vad som felade för dig. Kollade min kod, och där ser det ut att vara rätt straight forward:

    Kod:
    static class ForecastAdapter extends ArrayAdapter<DayEntry> {
    
    	public ForecastAdapter(Activity context, ArrayList<DayEntry> entries) {
    		super(context, 0, entries);
    	}
    
    	@Override
    	public View getView(int position, View convertView, ViewGroup parent) {
    		if (convertView == null) {
    			LayoutInflater inflater = context.getLayoutInflater();
    			convertView = inflater.inflate(R.layout.details_heading, null);
    			convertView.setTag(new ViewHandler(convertView));
    			setSizes(convertView);
    		}
    
    		populateView(convertView, entries.get(position));
    		return convertView;
    	}
    
    }
    
    Jag har utelämnat en del kod, men detta borde räcka som exempel
     
  5. Sigma78

    Sigma78 Teen Droid Medlem

    Blev medlem:
    27 jul 2010
    Inlägg:
    360
    Mottagna gillanden:
    6

    MINA ENHETER

    Ok, då är jag på rätt spår iaf, jag får titta vidare på det på måndag när jag är tillbaka på jobb.

    Tack för exempel koden!

    Sent from my GT-I9000 using Tapatalk
     
  6. Sigma78

    Sigma78 Teen Droid Medlem

    Blev medlem:
    27 jul 2010
    Inlägg:
    360
    Mottagna gillanden:
    6

    MINA ENHETER

    Jag får inte det att fungera. Så här ser min kod ut:

    Kod:
    	protected class WebObject {
    
    		public Spanned Text=Html.fromHtml("");
    		public String Link="";
    		public boolean IgnoreInHistory=false; 
    /*
    		public void onCreate()
    		{
    			Text=Html.fromHtml("");
    			Link="";
    			IgnoreInHistory=false;
    		}*/
    		
    		public View getView(int position, View convertView, ViewGroup parent) {
    		
    	    	Toast.makeText(ForumTab.this,"WebObject getView körs", Toast.LENGTH_LONG).show();
    			TextView v=new TextView(ForumTab.this);
    			v.setText("Hej");
    			return v;
    		}
    		
    		public String toString(){
    			return Text.toString();
    		}
    	
    		public Spanned getTextSpanned(){
    			return Text;
    		}
    	}
    
    toString anropas, men inte getView.

    Jag har nog gjort något annat grundläggande fel också, för onCreate körs inte när man instansierar med WebObject a=new WebObject();
    Jag trodde att det var konstruktorn...
     
  7. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    Kanske skulle ha förklarat min kod lite :)

    Nej, onCreate är inte en konstruktor. En konstruktor i Java har alltid samma namn som klassen. I ditt fall ser WebObject ut som ett value object, eller modell. Kalla det vad man vill, men konstruktorn skall heta WebObject.

    onCreate är en särskild metod som man kan överlagra när man ärver Aktiviteter i Android. Ditt value object är inte en aktivitet, och ingår därför inte i Androids "livscykel".

    Metoden getView är en metod som tillhör klassen ArrayAdapter, så det du skall göra är en subklass till ArrayAdapter, och där överlagra getView, så som jag gjort i mitt exempel. Istället för att instantiera en ArrayAdapter skall du sedan instantiera din subklass (vilket är ForecastAdapter i mitt fall). Mina value objects var av typen Forecast, men den syns inte i exemplet iom att den inte gör något viktigt.
     
    Sigma78 gillar detta.
  8. Sigma78

    Sigma78 Teen Droid Medlem

    Blev medlem:
    27 jul 2010
    Inlägg:
    360
    Mottagna gillanden:
    6

    MINA ENHETER

    Ah, där ser man! Tack för förklaringarna!
    Jag tyckte att det verkade onödigt att ärva något för en så enkel klass, jobbet att instansiera blir väl betydligt större då? Men om det är ett krav för att få den här funktionaliteten att fungera är det inte mycket att be för.
    Precis som du säger är det bara en bärare av två variabler, vad nu det korrekta uttrycket för det är. Struct hette det på den tiden jag senast programmerade. :)

    Jag ska prova att ärva från ArrayAdapter och se om det avhjälper problemet.

    WebObject är en intern klass som ingår i en huvudklass. Huvudklassen ärver från Activity, men jag tror inte att det påverkar.
     
    Last edited: 3 jan 2011
  9. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    Nä, det enda man gör är ändrar från new ArrayAdapter(....) till new YourAdapter(....)
     
  10. Sigma78

    Sigma78 Teen Droid Medlem

    Blev medlem:
    27 jul 2010
    Inlägg:
    360
    Mottagna gillanden:
    6

    MINA ENHETER

    Det var inte mitt jobb jag tänkte på, utan för enheten som ska göra det :)
    Att instansiera upp en klass som bara innehåller två medlemsvariabler kräver nästintill inget minne och troligen väldigt få processorcykler, men en arrayadapter innehåller så väldigt mycket mer som jag inte behöver.

    Om det löser problemet är jag nog nöjd med det ändå :)
     
  11. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    I första inlägget skrev du "ListView med tillhörande ArrayAdapter". Alltså har du redan en ArrayAdapter :)

    Att (för telefonen) skapa en instans av en subklass tar inte mycket mer minne.
     
  12. Sigma78

    Sigma78 Teen Droid Medlem

    Blev medlem:
    27 jul 2010
    Inlägg:
    360
    Mottagna gillanden:
    6

    MINA ENHETER

    Ja, jag har en arrayadapter, men WebObjekt skapar jag massvis av. De representerar bara innehållet i ett objekt i listan medans ArrayAdaptern som jag har håller reda på allt listan innehåller.

    Om WebObjekt ärver från ArrayAdapter kommer jag att få en ArrayAdapter som innehåller en lista med ArrayAdapters. Det gör kanske inget?

    Jag får inte den att ta det fortfarande. Den använder sig av toString ändå. Så här ser koden ut (jag tar med lite mer runtomkring om det har någon inverkan):
    Kod:
    public class ForumTab extends TabBase {
    	/** Called when the activity is first created. */
    
    	private ProgressDialog progressDialog;
    	private ArrayAdapter<WebObject> WebObjectListAdapter;
    // En massa variabeldeklarationer bortklippta
    
    	protected class WebObject extends ArrayAdapter
    // Eclipse sätter ut en varning på raden ovan "ArrayAdapter is a raw type. References to generic type ArrayAdapter<T> should be parameterized"
    
    	{
    		
    		public WebObject(Context context, int textViewResourceId) {
    			super(context, textViewResourceId);
    			Text=Html.fromHtml("");
    			Link="";
    			IgnoreInHistory=false;
    		}
    
    		public Spanned Text=Html.fromHtml("");
    		public String Link="";
    		public boolean IgnoreInHistory=false; 
    	
    		@Override
    		public View getView(int position, View convertView, ViewGroup parent) {
    			
    	    	Toast.makeText(ForumTab.this,"WebObject getView körs", Toast.LENGTH_LONG).show();
    			TextView v=new TextView(ForumTab.this);
    			v.setText("Hej");
    			return v;
    		}
    		public String toString(){
    			return Text.toString();
    		}
    	
    	}
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    // En massa onStart-grejs bortklippt
    }
    
    }
    Koden som fyller listan:
    Kod:
    	
    private String FirstLevelHeading(String HTMLCode)
    	{
       	
        	ArrayList<WebObject> WebObjectList;
        	
    	    	WebObjectList=FormatFirstLevelHeading(HTMLCode);
        	WebObjectListAdapter=new ArrayAdapter<WebObject>(this, R.layout.forumpostrow, WebObjectList);
        	try{
        	ListView.setAdapter( WebObjectListAdapter );
        	}
        	catch (Exception e)
        	{
    	    	Toast.makeText(ForumTab.this, "Fel vid Listvisning: " + e.getMessage(), Toast.LENGTH_LONG).show();
        	}
        	if(progressDialog!=null)
        		{
        		progressDialog.dismiss();
        		}
    		return HTMLCode;
    	}
    			    
    	private ArrayList<WebObject> FormatFirstLevelHeading(String HTMLCode)
    	{
    		
    		String Heading="";
    		String Link="";
        	ArrayList<WebObject> HeadingList=new ArrayList<WebObject>();
    		
    		int i=0;
    		while(HTMLCode.contains("<strong>") && i<500)
    		{
    		i++;
    		if(HTMLCode.indexOf("<strong>")>=0 && HTMLCode.indexOf("</strong>")>=0)
    			{
    			Heading=HTMLCode.substring(HTMLCode.indexOf("<strong>")+8,HTMLCode.indexOf("</strong>"));
    			WebObject MyWebObject=new WebObject(this, 0);
    			MyWebObject.Text=Html.fromHtml(Heading);
    
    			Link=Heading.substring(Heading.indexOf("<a href")+9,Heading.indexOf(">")-1);
    			Heading=Heading.substring(Heading.indexOf(">")+1,Heading.indexOf("</a>"));
    
    			MyWebObject.Link=Link;
    			HeadingList.add(MyWebObject);
    			}
    			HTMLCode=HTMLCode.substring(HTMLCode.indexOf("</strong>")+9);			
    		}
    		if(i>=500)
    		{
    	    	Toast.makeText(this, "Ajdå, i=1000", Toast.LENGTH_LONG).show();
    	    	Heading="Ajdå, i=1000";
    		}
    
    		return HeadingList;
    	}
    
     
    Last edited: 3 jan 2011
  13. Kaj

    Kaj Senior Droid Medlem

    Blev medlem:
    12 jun 2009
    Inlägg:
    1 768
    Mottagna gillanden:
    44

    MINA ENHETER

    Alltså dina WebObjekt skall inte ärva ArrayAdapter. Dina WebObjekt skall fortfarande se ut liknandes:

    Kod:
    protected class WebObject {
    
    		public Spanned Text=Html.fromHtml("");
    		public String Link="";
    		public boolean IgnoreInHistory=false; 
    		
    		public String toString(){
    			return Text.toString();
    		}
    	
    		public Spanned getTextSpanned(){
    			return Text;
    		}
    	}
    
    Sedan skall du skapa en subklass till ArrayAdapter. När du skapar den skall du skapa den liknandes så som jag skapade min ForecastAdapter. I din aktivitet skall du sedan skapa listan med en ArrayAdapter som är den subklass du skrivit.
     
    Sigma78 gillar detta.
  14. afzkl

    afzkl Youth Droid Medlem

    Blev medlem:
    27 aug 2009
    Inlägg:
    184
    Mottagna gillanden:
    6

    MINA ENHETER

    Hejsan. Hag tror du har missupfattat lite vad Kaj menade. Ditt webobjekt ska inte extend ArrayAdapter. Du ska endast ha en Adapter till din listview.

    Ditt WebObject är som en struct i c/c++ (om du är van vid att arbeta i det). Det innehåller endast datan din listview ska visa. Varje WebObject representerar en rad i listan.

    Dit WebObject skulle då kunna se ut såhär:
    Kod:
    public class WebObject {
    
    	private Spanned 		mText = Html.fromHtml("");
    	private String 			mLink = "";
    	private boolean 		ignoreInHistory=false;
    	
    	public Spanned getText() {
    		return mText;
    	}
    	
    	public void setText(Spanned text) {
    		this.mText = text;
    	}
    	
    	public String getLink() {
    		return mLink;
    	}
    	
    	public void setLink(String link) {
    		this.mLink = link;
    	}
    
    	public boolean isIgnoreInHistory() {
    		return ignoreInHistory;
    	}
    	
    	public void setIgnoreInHistory(boolean ignoreInHistory) {
    		this.ignoreInHistory = ignoreInHistory;
    	} 
    	
    	
    }
    
    Och din adapter skulle kunna se ut såhär:
    Kod:
    public class WebObjectAdapter extends ArrayAdapter<WebObject>{
    
    	LayoutInflater mInflater;
    	
    	public WebObjectAdapter(Context context, int textViewResourceId, List<WebObject> objects) {
    		super(context, textViewResourceId, objects);
    		
    		mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    	}
    	
    	@Override
    	public View getView(int position, View convertView, ViewGroup parent) {
    		
    		View v = convertView;
    		
    		if(v == null){			
    			v = mInflater.inflate(R.layout.forumpostrow, null);
    		}
    		
    		TextView title = (TextView) v.findViewById(R.id.title);
    		TextView link = (TextView) v.findViewById(R.id.link);
    		
    		title.setText(this.getItem(position).getText());
    		link.setText(this.getItem(position).getLink());
    		
    		
    		return v;
    	}
    	
    
    }
    

    När du sedan skapat en lista av alla din WebObject så skapar du en adapter:
    Kod:
    WebObjectAdapter a = new WebObjectAdapter(this, R.layout.forumrowpost, listOfWebobjects);
    mListView.setAdapter(a);
    
     
    Sigma78 gillar detta.
  15. Sigma78

    Sigma78 Teen Droid Medlem

    Blev medlem:
    27 jul 2010
    Inlägg:
    360
    Mottagna gillanden:
    6

    MINA ENHETER

    Ah, där trillade poletten ner :-)

    Nu får jag den att exekveras!

    Edit: Och inte bara det, den visar det jag vill också :-D Tack båda två för bra förklaringar!
    Jag var helt inne på att det var något jag skulle implementera i min WebObject-klass för att få det att fungera.
     
    Last edited: 3 jan 2011