I extended the android CardView to a Expandable version of it, with a header title and an icon which can be rotated.
CODE
This file(view_cardview_header.xml) contains the header of the ExpandableCardView, it should be the first child and not collapsed.
<?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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textAppearance="#style/TextAppearance.AppCompat.Title" />
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true" />
</RelativeLayout>
</LinearLayout>
The attrs.xml file with custom xml parameters
<resources>
<declare-styleable name="ExpandableCardView">
<attr name="expanded" format="boolean" />
<attr name="headerTitle" format="string" />
<attr name="headerIcon" format="integer" />
</declare-styleable>
</resources>
The ExpandableCardView.java class
public class ExpandableCardView extends CardView {
private static final float ROTATION_NORMAL = 0.0f;
private static final float ROTATION_ROTATED = 180f;
private static final float PIVOT_VALUE = 0.5f;
private static final long ROTATE_DURATION = 200;
private boolean isExpanded;
public ExpandableCardView(Context context) {
this(context, null);
}
public ExpandableCardView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ExpandableCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ExpandableCardView, 0, 0);
String titleText = a.getString(R.styleable.ExpandableCardView_headerTitle);
final Drawable drawable = a.getDrawable(R.styleable.ExpandableCardView_headerIcon);
a.recycle();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.view_cardview_header, this, true);
final LinearLayout parent = (LinearLayout) getChildAt(0);
final RelativeLayout header = (RelativeLayout) parent.getChildAt(0);
final TextView titleTextView = (TextView) header.getChildAt(0);
titleTextView.setText(titleText);
final ImageView toggle = (ImageView) header.getChildAt(1);
if(drawable != null) {
toggle.setImageDrawable(drawable);
}
header.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
setExpanded(toggle, !isExpanded);
onExpansionToggled(toggle);
}
});
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if(getChildAt(0) == null || getChildAt(0).equals(child)) {
super.addView(child, index, params);
} else {
((LinearLayout) getChildAt(0)).addView(child);
}
}
private void setExpanded(ImageView toggle, boolean expanded) {
isExpanded = expanded;
final LinearLayout parent = (LinearLayout) getChildAt(0);
final int childCount = parent.getChildCount();
if(expanded) {
toggle.setRotation(ROTATION_ROTATED);
for(int i = childCount - 1; i > 0; i--) {
parent.getChildAt(i).setVisibility(VISIBLE);
}
} else {
toggle.setRotation(ROTATION_NORMAL);
for(int i = 1; i < childCount; i++) {
parent.getChildAt(i).setVisibility(GONE);
}
}
}
private void onExpansionToggled(ImageView toggle) {
RotateAnimation rotateAnimation = new RotateAnimation(ROTATION_ROTATED, ROTATION_NORMAL,
RotateAnimation.RELATIVE_TO_SELF, PIVOT_VALUE, RotateAnimation.RELATIVE_TO_SELF,
PIVOT_VALUE);
rotateAnimation.setDuration(ROTATE_DURATION);
rotateAnimation.setFillAfter(true);
toggle.startAnimation(rotateAnimation);
}
}
Fragment Layout for testing the new CardView(fragment_test.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.tecdroid.views.ExpandableCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/card_margin"
android:layout_marginBottom="#dimen/card_margin"
android:layout_marginLeft="#dimen/card_margin"
android:layout_marginRight="#dimen/card_margin"
app:headerTitle="TITLE"
app:headerIcon="#mipmap/ic_action_expand">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="First inner child"/>
</com.tecdroid.views.ExpandableCardView>
</LinearLayout>
Result on Emulator
PROBLEM
As you can see on the image, the first inner child(TextView), is not placed under the Relative Layout(Header).
First i thought i have to override the onMeasure(int widthMeasureSpec, int heightMeasureSpec) method, but the ExpandableCardView extends indirect the ViewGroup, where the onMeasure(int widthMeasureSpec, int heightMeasureSpec) method does it all for me.
Maybe someone figure out what i have forgot, or did wrong.
UPDATE
Problem solved, see changes.
CardView extends FrameLayout, your header and first child are just unrelated child views. To have a spatial relation between children you need to use a LinearLayout or RelativeLayout with align-* parameters.
why not make a compound view with your cardview and a layout of your choice that contains the child view?
Related
Please assist me with implementing MP Line Chart in ListView; it works good in recycler view, however it loses its size as I add more than 5 items.
Because of the scroll view, I'm using an expanded listView to reduce issues, yet the chart looks like this.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_margin="10sp"
android:orientation="vertical"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#color/black"
android:text="#string/most_active_stocks"/>
<LinearLayout
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
android:gravity="center"
android:layout_margin="10sp">
<Button
android:layout_width="wrap_content"
android:textSize="10sp"
android:layout_gravity="center"
android:layout_height="40dp"
android:layout_margin="5dp"
android:background="#drawable/virtualtrading_button"
android:text="Volume"
android:gravity="center"
android:textColor="#color/black" />
<Button
android:layout_width="wrap_content"
android:layout_height="40dp"
android:textSize="10sp"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="#drawable/virtualtrading_button"
android:text="%Turnover"
android:gravity="center"
android:textColor="#color/black" />
<Button
android:layout_width="wrap_content"
android:layout_height="40dp"
android:textSize="10sp"
android:layout_margin="5dp"
android:layout_gravity="center"
android:background="#drawable/virtualtrading_button"
android:text="Range"
android:gravity="center"
android:textColor="#color/black" />
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.catalyst.maksl.Components.ExpandableHeightListView
android:id="#+id/moverlist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:drawSelectorOnTop="false"
android:fadingEdge="vertical"
android:divider="#android:color/transparent"
android:dividerHeight="5dp"
android:fitsSystemWindows="true"
android:listSelector="#00000000"
android:scrollbars="none"
android:smoothScrollbar="true" />
</RelativeLayout>
</LinearLayout>
ExpandableListView Class
public class ExpandableHeightListView extends ListView {
boolean expanded = false;
public ExpandableHeightListView(Context context)
{
super(context);
}
public ExpandableHeightListView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ExpandableHeightListView(Context context, AttributeSet attrs,int defStyle)
{
super(context, attrs, defStyle);
}
public boolean isExpanded()
{
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// HACK! TAKE THAT ANDROID!
if (isExpanded())
{
// Calculate entire height by providing a very large height hint.
// But do not use the highest 2 bits of this integer; those are
// reserved for the MeasureSpec mode.
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}
adapter class :
public class MostActiveStocksAdapter extends BaseAdapter {
private static LineDataSet set1;
public static Drawable drawablePositive = ContextCompat.getDrawable(Logs.globalContext, R.drawable.graph_green_bg);
public static Drawable drawable_negative = ContextCompat.getDrawable(Logs.globalContext, R.drawable.graph_bg);
Context context;
private Double changePercentage;
ArrayList<String> arrayList = new ArrayList<String>();
LayoutInflater mInflater = null;
private ViewHolder holder;
public ArrayList<Entry> values;
public LineData data;
public MostActiveStocksAdapter(Context context, ArrayList<String> arrayList) {
this.context = context;
this.arrayList = arrayList;
mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return arrayList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.most_active_stocks_listitem, null);
holder = new ViewHolder();
holder.moverSymbolName = (TextView) convertView.findViewById(R.id.moversymbolName);
holder.moverScripName = (AutoResizeTextView) convertView.findViewById(R.id.moversmainSymbolName);
holder.moverLastTradePrice = (TextView) convertView.findViewById(R.id.moverslastTradePrice);
holder.moverchange = (AutoResizeTextView) convertView.findViewById(R.id.moversindexChange);
holder.moverMarket = (TextView) convertView.findViewById(R.id.moverssymbolMarket);
holder.sector = convertView.findViewById(R.id.movertextSector);
holder.nameIcon = convertView.findViewById(R.id.moverNameicon);
holder.masLineChart = convertView.findViewById(R.id.moversgraph);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
ScripBean scripBean = Logs.allScripBean.get(arrayList.get(position));
MostActiveStockMarketFeedBean marketFeedBean = Logs.mostActiveStockMarketFeedBeanHashMap.get(arrayList.get(position));
if (marketFeedBean != null) {
changePercentage = marketFeedBean.getChange() / (marketFeedBean.getLastTradePrice() - marketFeedBean.getChange()) * 100;
holder.moverScripName.setText(marketFeedBean.getScrip());
holder.moverSymbolName.setText(marketFeedBean.getScripName());
holder.sector.setText(scripBean.getSectorName());
holder.nameIcon.setText(marketFeedBean.getScrip().substring(0,1));
holder.moverLastTradePrice.setText(Logs.priceFormat.format(marketFeedBean.getLastTradePrice()).replace("-", ""));
setData(5,3);
customiseChart();
if(marketFeedBean.getChange() != 0.0) {
if (Logs.priceFormat.format(changePercentage).contains("-")) {
holder.moverLastTradePrice.setBackground(context.getResources().getDrawable(R.drawable.bg_negativecell));
}
else
{
holder.moverLastTradePrice.setBackground(context.getResources().getDrawable(R.drawable.bg_positivecell));
}
holder.moverchange.setText(marketFeedBean.getChange() + " " + "(" + Logs.priceFormat.format(changePercentage).replace("-", "") + "%)");
}
else
{
holder.moverchange.setText("(0.00%)");
}
}
else {
String sm = arrayList.get(position);
holder.moverScripName.setText(sm.split("\\:", -1)[0]);
holder.moverMarket.setText(sm.split("\\:", -1)[1]);
holder.moverSymbolName.setText("");
holder.moverLastTradePrice.setText("0.00");
holder.moverchange.setText("0.00");
}
return convertView;
}
private void setData(int count, float range) {
values = new ArrayList<>();
for (int i = 0; i < count; i++) {
float val = (float) (Math.random() * range) - 30;
values.add(new Entry(i, val));
}
set1 = new LineDataSet(values, "DataSet 1");
set1.setDrawCircles(false);
set1.setDrawFilled(true);
set1.setLineWidth(1f);
set1.setColor(Color.GREEN);
set1.setMode(LineDataSet.Mode.CUBIC_BEZIER);
set1.setDrawFilled(true);
set1.setFillDrawable(drawablePositive);
set1.setFillFormatter(new IFillFormatter() {
#Override
public float getFillLinePosition(ILineDataSet dataSet, LineDataProvider dataProvider) {
return holder.masLineChart.getAxisLeft().getAxisMinimum();
}
});
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
dataSets.add(set1);
data = new LineData(dataSets);
holder.masLineChart.setData(data);
}
private void customiseChart()
{
holder.masLineChart.getDescription().setEnabled(false);
holder.masLineChart.setDrawGridBackground(false);
holder.masLineChart.setDragEnabled(false);
holder.masLineChart.getLegend().setEnabled(false);
holder.masLineChart.setScaleEnabled(true);
holder.masLineChart.setScaleYEnabled(false);
holder.masLineChart.setScaleXEnabled(true);
holder.masLineChart.setDrawGridBackground(false);
holder.masLineChart.getXAxis().setEnabled(false);
holder.masLineChart.getLineData().setDrawValues(false);
holder.masLineChart.getXAxis().setDrawGridLines(false);
holder.masLineChart.getXAxis().setDrawAxisLine(false);
holder.masLineChart.getAxisLeft().setDrawGridLines(false);
holder.masLineChart.getAxisRight().setDrawGridLines(false);
holder.masLineChart.getAxisRight().setDrawZeroLine(true);
holder.masLineChart.getAxisLeft().setDrawZeroLine(true);
holder.masLineChart.getAxisRight().setDrawLabels(false);
holder.masLineChart.getAxisLeft().setDrawLabels(false);
holder.masLineChart.getAxisLeft().setEnabled(false);
holder.masLineChart.getAxisRight().setEnabled(true);
holder.masLineChart.getAxisRight().setZeroLineColor(Color.BLACK);
holder.masLineChart.getAxisRight().setAxisLineColor(Color.BLACK);
holder.masLineChart.setMaxHighlightDistance(150);
holder.masLineChart.setViewPortOffsets(0, 0, 0, 0);
holder.masLineChart.setTouchEnabled(false);
holder.masLineChart.setPinchZoom(false);
}
private class ViewHolder {
TextView moverSymbolName;
TextView moverMarket;
AutoResizeTextView moverScripName;
TextView moverLastTradePrice;
AutoResizeTextView moverchange;
TextView sector;
TextView nameIcon;
LineChart masLineChart;
}
P.S: this ListView is in fragment.
Within my current Android application, I have a screen that displays an android.support.v4.app.DialogFragment.
This DialogFragment view contains the following UI components
HEADING
== Sub Heading
== NestedScrollView
==== RecyclerView
==== RadioGroup
==== Spinner
==== EditText
==== Action Buttons
The DialogFragment is configured to be Full Screen using Style as follows:-
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.AppDialogTheme);
}
My dialog style is
<!-- Define your custom dialog theme here extending from base -->
<style name="AppDialogTheme" parent="Theme.AppCompat.Light.Dialog">
<!-- Define color properties as desired -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#000</item>
<item name="android:textColorHighlight">#color/background_url</item>
<item name="colorAccent">#color/dark_grey</item>
<item name="colorControlNormal">#color/colorPrimaryDark</item>
<!-- Define window properties as desired -->
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowBackground">#android:color/white</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowCloseOnTouchOutside">false</item>
</style>
The reason I employ a NestedScrollView is so that the View will work in both Portrait and Landscape mode.
I wish to limit the height of the RecyclerView
The closest I have got is using the layout below.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/headline_literal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:padding="10dp"
android:text="Heading"
android:textSize="20sp"
android:textStyle="bold" />
<View
android:id="#+id/divider"
android:layout_width="fill_parent"
android:layout_height="2dp"
android:layout_marginTop="5dp"
android:background="#c0c0c0" />
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="5"
android:orientation="vertical">
<TextView
android:id="#+id/sub_headline_literal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="Some long texts having a long size so that it takes multiple lines in the view to replicate the real-life app use case. This is important to have 3-4 lines this textview so that we can see if the views are being populated correctly. Hope this sentence is long enough to replicate the real-life scenario of this TextView content. Thank you."
android:textSize="16sp"
android:textStyle="normal" />
<android.support.v7.widget.RecyclerView
android:id="#+id/dummy_rv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="10dp"
android:layout_marginStart="9dp"
android:layout_marginEnd="9dp"
android:layout_weight="1"
android:background="#drawable/rv_border"
android:fadingEdge="horizontal"
android:fadingEdgeLength="10dp"
android:padding="10dp"
android:requiresFadingEdge="vertical" />
<RadioGroup
android:id="#+id/myRadioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:checkedButton="#+id/sound">
<RadioButton
android:id="#+id/sound"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sound" />
<RadioButton
android:id="#+id/vibration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vibration" />
<RadioButton
android:id="#+id/silent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Silent" />
</RadioGroup>
<EditText
android:id="#+id/notes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Notes" />
<LinearLayout
android:id="#+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="#+id/cancel_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Cancel" />
<TextView
android:id="#+id/submit_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Submit" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
By using weightSum on the inner LinearLayout of the NestedScrollView I can limit the height of the Recyclerview. However the NestedScrollView height is far too large, with more than half its height being blank.
How can I limit the height of my RecyclerView and get NestedScrollView to wrap_content?
I've tried NestedScrollView with height wrap_content but this has no effect.
How can I achieve the desired UI? Thanks in advance!
Instead of having a NestedRecyclerView, I would like to suggest to have a header and a footer added to your RecyclerView which will nicely place the overall content as far as I have seen your layout. I want to provide you a link to my answer here where you can find how to add a footer and a header along with your RecyclerView.
Hence, I would like to suggest to create a view with headline_literal and the divider and use this as a header whereas the RadioGroup, EditText and the Button will be in the footer. Let me know if you face any problem with it.
I have tried to implement the behavior that you want by myself and let me know if the following implementation works for you. I have added this in Github as well.
Let us first declare an adapter for adding a header and a footer to the RecyclerView.
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
public class RecyclerViewWithHeaderFooterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int FOOTER_VIEW = 1;
private static final int HEADER_VIEW = 2;
private ArrayList<String> data; // Take any list that matches your requirement.
private Context context;
// Define a constructor
public RecyclerViewWithHeaderFooterAdapter(Context context, ArrayList<String> data) {
this.context = context;
this.data = data;
}
// Define a ViewHolder for Header view
public class HeaderViewHolder extends ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// Define a ViewHolder for Footer view
public class FooterViewHolder extends ViewHolder {
public FooterViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// Now define the ViewHolder for Normal list item
public class NormalViewHolder extends ViewHolder {
public NormalViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do whatever you want on clicking the normal items
}
});
}
}
// And now in onCreateViewHolder, you have to pass the correct view
// while populating the list item.
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
if (viewType == FOOTER_VIEW) {
v = LayoutInflater.from(context).inflate(R.layout.list_item_footer, parent, false);
FooterViewHolder vh = new FooterViewHolder(v);
return vh;
} else if (viewType == HEADER_VIEW) {
v = LayoutInflater.from(context).inflate(R.layout.list_item_header, parent, false);
HeaderViewHolder vh = new HeaderViewHolder(v);
return vh;
}
// Otherwise populate normal views
v = LayoutInflater.from(context).inflate(R.layout.list_item_normal, parent, false);
NormalViewHolder vh = new NormalViewHolder(v);
return vh;
}
// Now bind the ViewHolder in onBindViewHolder
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
try {
if (holder instanceof NormalViewHolder) {
NormalViewHolder vh = (NormalViewHolder) holder;
vh.bindView(position);
} else if (holder instanceof FooterViewHolder) {
FooterViewHolder vh = (FooterViewHolder) holder;
} else if (holder instanceof HeaderViewHolder) {
HeaderViewHolder vh = (HeaderViewHolder) holder;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Now the critical part. You have return the exact item count of your list
// I've only one footer. So I returned data.size() + 1
// If you've multiple headers and footers, you've to return total count
// like, headers.size() + data.size() + footers.size()
#Override
public int getItemCount() {
if (data == null) {
return 0;
}
if (data.size() == 0) {
// Return 1 here to show nothing
return 1;
}
// Add extra view to show the header view
// Add another extra view to show the footer view
// So there are two extra views need to be populated
return data.size() + 2;
}
// Now define getItemViewType of your own.
#Override
public int getItemViewType(int position) {
if (position == 0) {
// This is where we'll add the header.
return HEADER_VIEW;
} else if (position == data.size() + 1) {
// This is where we'll add a footer.
return FOOTER_VIEW;
}
return super.getItemViewType(position);
}
// So you're done with adding a footer and its action on onClick.
// Now set the default ViewHolder for NormalViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {
// Define elements of a row here
public ViewHolder(View itemView) {
super(itemView);
// Find view by ID and initialize here
}
public void bindView(int position) {
// bindView() method to implement actions
}
}
}
Now let us define the layouts one by one. Here is the list_item_normal.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="wrap_content">
<TextView
android:id="#+id/normal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="This is a text to be displayed in each item in the RecyclerView"
android:textSize="16sp"
android:textStyle="normal" />
</LinearLayout>
And the list_item_footer.xml should look like the following.
<?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="wrap_content"
android:layout_marginTop="16dp"
android:orientation="vertical">
<RadioGroup
android:id="#+id/myRadioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:checkedButton="#+id/sound">
<RadioButton
android:id="#+id/sound"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sound" />
<RadioButton
android:id="#+id/vibration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vibration" />
<RadioButton
android:id="#+id/silent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Silent" />
</RadioGroup>
<EditText
android:id="#+id/notes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Notes" />
<LinearLayout
android:id="#+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="#+id/cancel_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Cancel" />
<TextView
android:id="#+id/submit_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Submit" />
</LinearLayout>
</LinearLayout>
Finally, the list_item_header.xml should have the following.
<?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="wrap_content">
<TextView
android:id="#+id/sub_headline_literal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="Some long texts having a long size so that it takes multiple lines in the view to replicate the real-life app use case. This is important to have 3-4 lines this textview so that we can see if the views are being populated correctly. Hope this sentence is long enough to replicate the real-life scenario of this TextView content. Thank you."
android:textSize="16sp"
android:textStyle="normal" />
</LinearLayout>
Now you have divided the components of your original layout into parts. Hence the main layout should look like the following.
<?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="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/headline_literal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:padding="10dp"
android:text="Heading"
android:textSize="20sp"
android:textStyle="bold" />
<View
android:id="#+id/divider"
android:layout_width="fill_parent"
android:layout_height="2dp"
android:layout_marginTop="5dp"
android:background="#c0c0c0" />
<android.support.v7.widget.RecyclerView
android:id="#+id/dummy_rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:padding="10dp" />
</LinearLayout>
Hence, I am sharing one sample Activity to run this code which will show the overall implementation.
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private ArrayList<String> data = new ArrayList<String>();
private RecyclerViewWithHeaderFooterAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeData();
initializeRecyclerView();
}
private void initializeRecyclerView() {
mRecyclerView = findViewById(R.id.dummy_rv);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new RecyclerViewWithHeaderFooterAdapter(this, data);
mRecyclerView.setAdapter(adapter);
}
private void initializeData() {
for (int i = 0; i < 10; i++) data.add("Position :" + i);
}
}
Hope that helps!
Customize Recycler view to set maxHeight.
public class MaxHeightRecyclerView extends RecyclerView {
private int mMaxHeight;
public MaxHeightRecyclerView(Context context) {
super(context);
}
public MaxHeightRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context, attrs);
}
public MaxHeightRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize(context, attrs);
}
private void initialize(Context context, AttributeSet attrs) {
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);
mMaxHeight = arr.getLayoutDimension(R.styleable.MaxHeightScrollView_maxHeight, mMaxHeight);
arr.recycle();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mMaxHeight > 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
n attrs.xml
<declare-styleable name="MaxHeightScrollView">
<attr name="maxHeight" format="dimension" />
</declare-styleable>
set RecyclerView height wrap_content in xml and maxHeight to fixwidth in dp.
The RecyclerView will consume height wrap_content till fixWidth which you set, after reaching to maxHeight, the RecyclerView will scrollable.
If you also need to limit the size of your NestedScrollView by makeing a custom NestedScrollView:
public class CustomNestedScrollView extends NestedScrollView {
private int maxHeight;
private final int defaultHeight = 200;
public CustomNestedScrollView(Context context) {
super(context);
}
public CustomNestedScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode()) {
init(context, attrs);
}
}
public CustomNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (!isInEditMode()) {
init(context, attrs);
}
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CustomNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
if (!isInEditMode()) {
init(context, attrs);
}
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.CustomNestedScrollView);
//200 is a defualt value
maxHeight = styledAttrs.getDimensionPixelSize(R.styleable.CustomNestedScrollView_maxHeight, defaultHeight);
styledAttrs.recycle();
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
attr.xml
<declare-styleable name="CustomNestedScrollView">
<attr name="maxHeight" format="dimension" />
</declare-styleable>
example layout for custom NestedScrollView:
<your.package.CustomNestedScrollView
android:layout_weight="1"
app:maxHeight="90dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!--Child view with RecyclerView here-->
</your.package.CustomNestedScrollView>
Along with this custom NestedScrollView if you apply the customization of your RecyclerView then it will work exactly how you want. I hope this helps!
I have created a RecyclerView (in a fragment) in which I am adding items dynamically using GridLayoutManager. In each of the cell of RecyclerView I am loading images from the server using Picasso.
Now the problem is that, when the images are loading for the first time, the RecyclerView cells take weird height as shown here:
But when I change tab and come to the home tab again, everything is the way I want, as shown here:
What I need is, to make cells take the desired width and height at the time they are getting added to the recycler view. To achieve this I have tried:
Get the width of the screen and set cells' height and width = screen size /2.
Take the width of RecyclerView and make cells' width and height equals to half of it.
I am assigning dimensions to the cell in onCreateViewHolder method of the adapter.
But in any case, I need to change tab (load fragment again) to give the cells the desired height.
I have specified the width and height of cell in its layout file as wrap content because I want them to get set according to screen size. I don't wanna hard code any value.
What am I doing wrong? Did I miss anything?
For detailed explanation, the code is given as follows:
Cell layout file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/category_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#android:color/darker_gray"
android:orientation="vertical"
android:weightSum="1">
<ImageView
android:id="#+id/categoryImage"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:layout_marginTop="0dp"
android:layout_weight="0.8"
android:src="#drawable/icon" />
<TextView
android:id="#+id/categoryName"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="5dp"
android:layout_marginTop="0dp"
android:layout_weight="0.2"
android:text="ORAL CARE"
android:textAlignment="center"
android:textColor="#android:color/black"
android:textSize="15dp" />
</LinearLayout>
RecyclerView in fragment's layout file:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerViewCategories"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView11" />
RecyclerView adapter:
public class CategoryRecyclerViewAdapter extends RecyclerView.Adapter<CategoryRecyclerViewAdapter.ViewHolder> {
private List<MedicineCategoryDataModel> categoryData = new ArrayList<MedicineCategoryDataModel>();
private LayoutInflater layoutInflater;
private ItemClickListener itemClickListener;
private Context context;
private int itemWidth;
public CategoryRecyclerViewAdapter(Context context, List<MedicineCategoryDataModel> data, int width) {
this.layoutInflater = LayoutInflater.from(context);
this.categoryData = data;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.layout_category_item, parent, false);
// this is the point where I was trying to set cell's width and height.
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String categoryName = categoryData.get(position).categoryName;
holder.textViewCategoryName.setText(categoryName);
String iconUrl = categoryData.get(position).iconUrl;
EPClientLayer.getInstance().getImageHandler().loadImage(context,iconUrl, holder.imageViewCategoryIcon);
}
#Override
public int getItemCount() {
return categoryData.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView textViewCategoryName;
ImageView imageViewCategoryIcon;
ViewHolder(View itemView) {
super(itemView);
textViewCategoryName = (TextView) itemView.findViewById(R.id.categoryName);
imageViewCategoryIcon = (ImageView) itemView.findViewById(R.id.categoryImage);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (itemClickListener != null) itemClickListener.onItemClick(view, getAdapterPosition());
}
}
public String getItem(int id) {
return categoryData.get(id).categoryName;
}
public void setClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
I think you need to set the height of the ImageView of your cell item to wrap_content instead of providing the height 0dp as you are taking the weightSum. I would like to recommend to implement your cell items like this.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/category_item"
android:layout_width="match_parent"
android:layout_height="260dp"
android:background="#android:color/darker_gray">
<ImageView
android:id="#+id/categoryImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/icon" />
<TextView
android:id="#+id/categoryName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/categoryImage"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"
android:text="ORAL CARE"
android:textColor="#android:color/black"
android:textSize="15sp" />
</RelativeLayout>
And the RecyclerView to have the height and width set to match_parent.
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerViewCategories"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView11" />
You do not want to hard code any height, which is fine. However, I think you might consider hard-coding the optimized height of the cell item's root RelativeLayout to get the desired behaviour in all screen sizes.
make an SquareImageView as:
public class SquareImageView extends AppCompatImageView {
public SquareImageView(Context context) {
super(context);
}
public SquareImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);//replace heightMeasureSpec with widthMeasureSpec in this line
}
}
use above imageView in recyclerView Item to load image using Piccasa.
use recyclerView in xml as:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:spanCount="2"
tools:listitem="#layout/recycler_view_item"
app:layoutManager="GridLayoutManager">
</android.support.v7.widget.RecyclerView>
let me know if this solve your problem
I want Help to overlay a play icon on top of every grid item, if it contains video.Here is my Layout File of GridView. I was Trying to do, but i was not able to wire up all things.
Ps :- I am Newbie
<FrameLayout
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:padding="2dp"
tools:context="com.techx.storysaver.ImageFragment">
<GridView
android:id="#+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:horizontalSpacing="2dp"
android:listSelector="#drawable/griditem_selector"
android:numColumns="2"
android:drawSelectorOnTop="true"
android:stretchMode="columnWidth"
android:verticalSpacing="2dp" />
</FrameLayout>
Here is my ImageAdapter
public class ImageAdapter extends BaseAdapter {
private Context context;
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures";
File f = new File(path);
File file[] = f.listFiles();
public ImageAdapter(Context c) {
context = c;
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
#Override
public int getCount() {
return file.length;
}
#Override
public Object getItem(int position) {
return file[position];
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Arrays.sort(file, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
final String path = file[position].getAbsolutePath();
CheckableLayout l;
ImageView i;
if (convertView == null) {
i = new ImageView(context);
i.setScaleType(ImageView.ScaleType.CENTER_CROP);
int widthSize = getScreenWidth();
widthSize = widthSize / 2;
widthSize = widthSize - 8;
int heightSize = getScreenHeight();
heightSize = heightSize / 3;
heightSize = heightSize - 10;
i.setLayoutParams(new ViewGroup.LayoutParams(widthSize, heightSize));
i.setPadding(8, 8, 8, 8);
l = new CheckableLayout(context);
l.setLayoutParams(new GridView.LayoutParams(GridView.LayoutParams.WRAP_CONTENT, GridView.LayoutParams.WRAP_CONTENT));
l.addView(i);
} else {
l = (CheckableLayout) convertView;
i = (ImageView) l.getChildAt(0);
}
if (path.endsWith(".jpg") || path.endsWith(".jpeg") || path.endsWith(".png")) {
Glide
.with(context)
.load(file[position])
.into(i);
}
if (path.endsWith(".mp4")) {
Glide
.with(context)
.load(file[position])
.into(i);
}
return l;
}
public class CheckableLayout extends FrameLayout implements Checkable {
private boolean mChecked;
public CheckableLayout(Context context) {
super(context);
}
#SuppressWarnings("deprecation")
public void setChecked(boolean checked) {
mChecked = checked;
setBackgroundDrawable(checked ? getResources().getDrawable(R.drawable.item_selector) : null);
}
public boolean isChecked() {
return mChecked;
}
public void toggle() {
setChecked(!mChecked);
}
}
public static int getScreenWidth() {
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
public static int getScreenHeight() {
return Resources.getSystem().getDisplayMetrics().heightPixels;
}
}
1. Create an layout XML for your GridView Item.
grid_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/tools"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
card_view:cardCornerRadius="4dp"
card_view:cardUseCompatPadding="false"
card_view:cardPreventCornerOverlap="false">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:scaleType="centerCrop"
android:src="#drawable/sample_1" />
<ImageView
android:id="#+id/icon_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:src="#drawable/icon_play"/>
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/image"
android:padding="8dp"
android:background="#CCFFFFFF"
android:text="This is simple title"
android:textColor="#000000" />
</RelativeLayout>
</android.support.v7.widget.CardView>
2. Use grid_item.xml from your adapter getView() method for each item:
#Override
public View getView(int pos, View convertView, ViewGroup parent)
{
Arrays.sort(file, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
final String path = file[position].getAbsolutePath();
if(convertView == null)
{
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.grid_item, null);
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.image);
ImageView iconPlay= (ImageView) convertView.findViewById(R.id.icon_play);
TextView textTitle= (TextView) convertView.findViewById(R.id.title);
// Image
if (path.endsWith(".jpg") || path.endsWith(".jpeg") || path.endsWith(".png")) {
Glide
.with(context)
.load(file[position])
.into(imageView);
// Hide play icon
iconPlay.setVisibility(View.GONE);
}
// Video
if (path.endsWith(".mp4")) {
Glide
.with(context)
.load(file[position])
.into(imageView);
// Show play icon
iconPlay.setVisibility(View.VISIBLE);
}
return convertView;
}
OUTPUT:
Hope this will help~
I have an strange behavior of TextView it beats me how can I figure out a solution to this issue.
I have a layout
<?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="wrap_content"
android:gravity="start"
android:orientation="horizontal"
android:visibility="visible">
<View
android:id="#+id/them_avatar_spacer"
android:layout_width="#dimen/avatar_size"
android:layout_height="0.0dip"
android:visibility="gone"/>
<org.slabs.fc.chatstarter.ui.CircularImageView
android:id="#+id/them_avatar"
android:layout_width="#dimen/avatar_size"
android:layout_height="#dimen/avatar_size"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:src="#drawable/default_avatar"
android:visibility="gone"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4.0dip"
android:gravity="start"
android:orientation="vertical">
<TextView
android:id="#+id/chat_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="2.0dip"
android:layout_marginLeft="6.0dip"
android:layout_marginTop="6dp"
android:includeFontPadding="false"
android:text="Title"
android:textColor="#color/black_light"
android:textSize="#dimen/chat_name_fontsize"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:orientation="horizontal">
<TextView
android:id="#+id/chat_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="63.0dip"
android:autoLink="all"
android:background="#drawable/selectable_balloon_left"
android:clickable="true"
android:lineSpacingExtra="#dimen/text_body_line_spacing"
android:linksClickable="true"
android:text="Every message text comes here"
android:textColor="#color/black_heavy"
android:textIsSelectable="false"
android:textSize="#dimen/chat_text_msg_fontsize"
android:visibility="visible"/>
<TextView
android:id="#+id/chat_time"
android:layout_width="60.0dip"
android:layout_height="wrap_content"
android:layout_gravity="start|center"
android:layout_marginLeft="-60.0dip"
android:text="12:15"
android:textColor="#color/black_lightest"
android:textSize="#dimen/chat_timestamp_fontsize"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
It gives me desired layout in a Design option of XML editor, as shown
But when I run the App the TextView with id chat_text is not showing and I get a result like below,
Then I tried to create a custom TextView I simply created one as
public class ChatThemTextView extends TextView {
public ChatThemTextView(Context context) {
super(context);
}
public ChatThemTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ChatThemTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
ViewGroup.MarginLayoutParams margins = ViewGroup.MarginLayoutParams.class.cast(getLayoutParams());
int margin = 5;
margins.topMargin = margin;
margins.bottomMargin = margin;
margins.leftMargin = margin;
margins.rightMargin = margin;
setLayoutParams(margins);
}
}
At this point other issue came out which is when I add the first message I don't get anything but when I add the second message I get the background but TextView is still not showing as shown here
You all see what is expected how the output comes, any help is appreciated...
Update
ViewHolder is just simple
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
adapter class goes here
public class ChatMessageAdapter extends RecyclerView.Adapter<ViewHolder> {
private List<ChatMessage> mMessageList;
private Context mContext;
private boolean isMe = false;
public ChatMessageAdapter(Context mContext, List<ChatMessage> mMessageList){
this.mContext = mContext;
this.mMessageList = mMessageList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View rootView = View.inflate(mContext, R.layout.chat_them_container, null);
return new ThemMessageHolder(rootView);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
ThemMessageHolder messageHolder = (ThemMessageHolder) holder;
messageHolder.mMessageTextView.setText(mMessageList.get(position).getMessage());
messageHolder.mSentAtTextView.setText(mMessageList.get(position).getSentAt());
Log.e("MSG_TEXT", mMessageList.get(position).getMessage());
}
#Override
public int getItemCount() {
return mMessageList.size();
}
public void clearData() {
mMessageList.clear(); //clear list
this.notifyDataSetChanged();
}
}
important
I get the Sting value at
Log.e("MSG_TEXT", mMessageList.get(position).getMessage());
but TextView is not showing that String...
.gitignore is
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
and settings.gradle is just
include ':app'
You may change:
View rootView = View.inflate(mContext, R.layout.chat_them_container, null);
To:
View rootView = LayoutInflater.from(mContext).inflate(R.layout.chat_them_container, parent, false);
It will respect the LayoutParams of its parent, and hence fix your issue.