Chandler Davis
Chandler Davis

Reputation: 402

How to Create CardViews Dynamically in Android

I've been trying to get an app idea of mine to come to fruition for some time now. The idea is a weather app in which users can choose the content they want to see, and it is represented by cards (CardViews). For example, if they want to see only current weather and a 3 day forecast, they can enable that, and they'll see only those two cards in the MainActivity in a Google Now sort of fashion.

I've run into a few problems, and I need some help.

Firstly, how can I create the CardViews dynamically? My first attempt had the views completely defined in XML, but that didn't work very well because it doesn't seem very intuitive to hide/show them all the time. So I decided to extend the CardView class into things like a CurrentWeatherCardView and create the card completely programatically.

Here's the class I created from that. It's a child of the WeatherCardView class, which just extends CardView and doesn't do a whole lot else at this point.

package com.photonfighterlabs.particleweather.weathercardviews;

import android.app.Activity;
import android.content.Context;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.photonfighterlabs.particleweather.MainActivity;
import com.photonfighterlabs.particleweather.weatherobjects.CurrentWeather;
import com.photonfighterlabs.particleweather.weatherobjects.Weather;

import java.io.File;

import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;


public class CurrentWeatherCardView extends WeatherCardView {

private ViewGroup viewGroup;

private LinearLayout linearLayout_600, linearLayout_604, linearLayout_434;
private TextView cw_title, temp_text_view;
private ImageView icon_image_view;
private int is_day;
private CurrentWeather currentWeather;

public CurrentWeatherCardView(CurrentWeather currentWeather, Context context, Activity activity, ViewGroup viewGroup) {
    super(context, activity);
    this.currentWeather = currentWeather;
    this.currentWeather.initialize(context, activity, MainActivity.API_KEY);

    this.context = currentWeather.getContext();
    this.viewGroup = viewGroup;




    this.currentWeather.doOnResponse(() -> {
        setupLayout();
        setCw_title(currentWeather.getName(), currentWeather.getText());
        Weather.setIconDrawable(currentWeather.getIcon(), icon_image_view, currentWeather.getIs_day());
        setTemperature(currentWeather.getTemp_f());

    });

}

public CurrentWeatherCardView(Context context) {
    super(context);
}

public CurrentWeatherCardView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CurrentWeatherCardView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}





@Override
protected void setupLayout() {
    LayoutParams cardParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, pixels(200));
    cardParams.setMargins(
            pixels(15),
            pixels(15),
            pixels(15),
            0
    );
    super.setLayoutParams(cardParams);
    super.setRadius(pixels(4));
    super.setUseCompatPadding(true);



    linearLayout_604 = new LinearLayout(context);
    linearLayout_604.setBaselineAligned(false);
    linearLayout_604.setOrientation(VERTICAL);
    LayoutParams layout_170 = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    linearLayout_604.setLayoutParams(layout_170);
    this.addView(linearLayout_604);

    linearLayout_600 = new LinearLayout(context);
    linearLayout_600.setOrientation(LinearLayout.HORIZONTAL);
    LayoutParams layout_676 = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, pixels(50));
    linearLayout_600.setLayoutParams(layout_676);
    linearLayout_604.addView(linearLayout_600);

    cw_title = new TextView(context);
    cw_title.setTypeface(Typeface.SANS_SERIF);
    cw_title.setTextSize(pixels(5));
    LayoutParams layout_914 = new LayoutParams(pixels(250), pixels(25));
    layout_914.setMarginStart(pixels(10));
    layout_914.topMargin = pixels(10);
    cw_title.setLayoutParams(layout_914);
    linearLayout_600.addView(cw_title);


    icon_image_view = new ImageView(context);
    LayoutParams layout_501 = new LayoutParams(pixels(75), pixels(40));
    layout_501.setMarginStart(pixels(45));
    layout_501.topMargin = pixels(10);
    icon_image_view.setLayoutParams(layout_501);
    linearLayout_600.addView(icon_image_view);

    linearLayout_434 = new LinearLayout(context);
    linearLayout_434.setOrientation(HORIZONTAL);
    LayoutParams layout_204 = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    linearLayout_434.setLayoutParams(layout_204);

    temp_text_view = new TextView(context);
    temp_text_view.setTextAlignment(TEXT_ALIGNMENT_TEXT_START);
    temp_text_view.setTextSize(pixels(8));
    LayoutParams layout_725 = new LayoutParams(pixels(100), pixels(100));
    layout_725.setMarginStart(pixels(25));
    layout_725.topMargin = pixels(10);
    temp_text_view.setLayoutParams(layout_725);
    linearLayout_434.addView(temp_text_view);
    linearLayout_604.addView(linearLayout_434);

    viewGroup.addView(this);
}


private void setCw_title(String title, String condition) {
    cw_title.setText(title + " - " + condition);
}

private void setTemperature(double temp) {
    temp_text_view.setText(String.valueOf((int) temp) + '\u00b0');
}



}

It's messy, but is there a better way? Doing it this way allows me to create this CardView by just instantiating the class, but I'm running into issues with figuring out what kind of view I should put these in. RecyclerView doesn't really seem like the right choice because as far as I can tell it's creates cards from a dataset. In my case, the CurrentWeatherCardView will always be the same.

That leads me to my next question. In what way can I have a scrollable, side-swipeable set of cards? RecyclerView? ListView? I'm pretty lost, and any guidance would help.

Upvotes: 3

Views: 5505

Answers (1)

cy198706
cy198706

Reputation: 598

CardView is extended from FrameLayout, so you can just use a xml to design what your card looks like, and use findViewById in this CurrentWeatherCardView. For example:

    public CurrentWeatherCardView(Context context) {
    super(context);
    init();
}

public CurrentWeatherCardView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public CurrentWeatherCardView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

private void init() { 
    LayoutInflater.from(this).inflate(R.layout.xxx, this, true);
    xxx = findViewById(R.id.xxxxx);
    ...
    xxx.setText(xxxx)

    // if you want to change visibility, just call:
    setVisibility(View.GONE/View.VISIBILE);
}

Upvotes: 2

Related Questions