I want to create a RecyclerView in Android which contains ViewHolders, that change their width and height as shown in the GIF below. I tried several LayoutManagers for the RecyclerView but I did not manage to get the result I wished for.
The RecyclerView should be a 1 dimensional row.
Hi you can use this to animate the views inside your RecyclerView as shown on the GIF below:
My adapter:
public class StringAdapter extends RecyclerView.Adapter<StringAdapter.StringHolder> {
private int defaultWidth = 0;
private int defaultHeight = 0;
private static final String[] strings = new String[]{"Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 8", "Item 10"};
private int lastSelected = -1;
private final RecyclerView.LayoutManager layoutManager;
private static final int animValue = 50;
StringAdapter(RecyclerView.LayoutManager layoutManager) {
this.layoutManager = layoutManager;
}
#NonNull
#Override
public StringHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.test_holder, parent, false);
return new StringHolder(v);
}
#Override
public void onBindViewHolder(#NonNull StringHolder holder, int position) {
holder.categories.setText(strings[position]);
ViewGroup.LayoutParams param = holder.card.getLayoutParams();
if (position == lastSelected) {
param.width = defaultWidth + animValue;
param.height = defaultHeight + animValue;
} else {
if (defaultWidth != 0 && defaultHeight != 0) {
param.width = defaultWidth;
param.height = defaultHeight;
}
}
}
#Override
public int getItemCount() {
return strings.length;
}
protected class StringHolder extends RecyclerView.ViewHolder {
private final TextView categories;
private final CardView card;
public StringHolder(#NonNull View itemView) {
super(itemView);
categories = itemView.findViewById(R.id.categories);
card = itemView.findViewById(R.id.cardCategories);
card.setOnClickListener(v -> {
int currentPosition = this.getAbsoluteAdapterPosition();
selection(currentPosition, lastSelected);
lastSelected = currentPosition;
});
}
private void selection(int newPosition, int oldPosition) {
if (newPosition != oldPosition) {
ConstraintLayout newView = (ConstraintLayout) layoutManager.findViewByPosition(newPosition);
ConstraintLayout oldView = (ConstraintLayout) layoutManager.findViewByPosition(oldPosition);
if (newView != null) {
defaultWidth = card.getWidth();
defaultHeight = card.getHeight();
selectAnimate(newView.getChildAt(0));
}
if (oldView != null) {
deselectAnimate(oldView.getChildAt(0));
} else {
notifyItemChanged(oldPosition);
}
}
}
private void selectAnimate(View view) {
ValueAnimator select = ValueAnimator.ofInt(defaultWidth, defaultWidth + animValue);
select.setInterpolator(new AccelerateDecelerateInterpolator());
select.setDuration(300);
select.start();
select.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = (int) animation.getAnimatedValue();
layoutParams.height = (int) (animation.getAnimatedValue()) + defaultHeight - defaultWidth;
view.requestLayout();
}
});
}
private void deselectAnimate(View view) {
ValueAnimator select = ValueAnimator.ofInt(defaultWidth + animValue, defaultWidth);
select.setInterpolator(new AccelerateDecelerateInterpolator());
select.setDuration(300);
select.start();
select.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = (int) animation.getAnimatedValue();
layoutParams.height = (int) (animation.getAnimatedValue()) + defaultHeight - defaultWidth;
view.requestLayout();
}
});
}
}
}
My MainActivity :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false);
recyclerView.setLayoutManager(layoutManager);
StringAdapter adapter = new StringAdapter(layoutManager);
recyclerView.setAdapter(adapter);
}
}
My MainActivity Layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="match_parent"
tools:context=".test.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="300dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
And finaly this MyHolder Layout :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="5dp">
<androidx.cardview.widget.CardView
android:id="#+id/cardCategories"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="15dp"
app:cardUseCompatPadding="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="#+id/categories"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_gravity="center"
android:gravity="center"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:text="Some Text"
android:textSize="16sp" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
I have created a list view with multiple items in row. I have also created a search box above. I want to implement search functionality on the basis of particular fields of the list. How can I achieve this? Any help will be appreciated.
You have to use model, listview, and customadapter with filtering for this.
I have created a demo for this.
Suppose you have a model named Product, and you are displaying its content in a custom listview where name and price are displayed in a textview. I mean in a custom row having two textviews, and you want to filter the list by one of the field of custom row. Here I have filtered with "name"
Screenshots:
Initial
Filtered
Source code
Model
public class Product {
public String name;
public Integer price;
public Product(String name, Integer price) {
super();
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}
Activity with custom adapter and listview
public class MainActivity extends Activity {
private LinearLayout llContainer;
private EditText etSearch;
private ListView lvProducts;
private ArrayList<Product> mProductArrayList = new ArrayList<Product>();
private MyAdapter adapter1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initialize();
// Add Text Change Listener to EditText
etSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Call back the Adapter with current character to Filter
adapter1.getFilter().filter(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
private void initialize() {
etSearch = (EditText) findViewById(R.id.etSearch);
lvProducts = (ListView)findViewById(R.id.lvOS);
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mProductArrayList.add(new Product("a", 100));
mProductArrayList.add(new Product("b", 200));
mProductArrayList.add(new Product("c", 300));
mProductArrayList.add(new Product("d", 400));
mProductArrayList.add(new Product("e", 500));
mProductArrayList.add(new Product("f", 600));
mProductArrayList.add(new Product("g", 700));
mProductArrayList.add(new Product("h", 800));
mProductArrayList.add(new Product("i", 900));
mProductArrayList.add(new Product("j", 1000));
mProductArrayList.add(new Product("k", 1100));
mProductArrayList.add(new Product("l", 1200));
mProductArrayList.add(new Product("m", 1000));
mProductArrayList.add(new Product("n", 1300));
mProductArrayList.add(new Product("o", 1400));
mProductArrayList.add(new Product("p", 1500));
adapter1 = new MyAdapter(MainActivity.this, mProductArrayList);
lvProducts.setAdapter(adapter1);
}
// Adapter Class
public class MyAdapter extends BaseAdapter implements Filterable {
private ArrayList<Product> mOriginalValues; // Original Values
private ArrayList<Product> mDisplayedValues; // Values to be displayed
LayoutInflater inflater;
public MyAdapter(Context context, ArrayList<Product> mProductArrayList) {
this.mOriginalValues = mProductArrayList;
this.mDisplayedValues = mProductArrayList;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return mDisplayedValues.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
private class ViewHolder {
LinearLayout llContainer;
TextView tvName,tvPrice;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.row, null);
holder.llContainer = (LinearLayout)convertView.findViewById(R.id.llContainer);
holder.tvName = (TextView) convertView.findViewById(R.id.tvName);
holder.tvPrice = (TextView) convertView.findViewById(R.id.tvPrice);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvName.setText(mDisplayedValues.get(position).name);
holder.tvPrice.setText(mDisplayedValues.get(position).price+"");
holder.llContainer.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast.makeText(MainActivity.this, mDisplayedValues.get(position).name, Toast.LENGTH_SHORT).show();
}
});
return convertView;
}
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,FilterResults results) {
mDisplayedValues = (ArrayList<Product>) results.values; // has the filtered values
notifyDataSetChanged(); // notifies the data with new filtered values
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults(); // Holds the results of a filtering operation in values
ArrayList<Product> FilteredArrList = new ArrayList<Product>();
if (mOriginalValues == null) {
mOriginalValues = new ArrayList<Product>(mDisplayedValues); // saves the original data in mOriginalValues
}
/********
*
* If constraint(CharSequence that is received) is null returns the mOriginalValues(Original) values
* else does the Filtering and returns FilteredArrList(Filtered)
*
********/
if (constraint == null || constraint.length() == 0) {
// set the Original result to return
results.count = mOriginalValues.size();
results.values = mOriginalValues;
} else {
constraint = constraint.toString().toLowerCase();
for (int i = 0; i < mOriginalValues.size(); i++) {
String data = mOriginalValues.get(i).name;
if (data.toLowerCase().startsWith(constraint.toString())) {
FilteredArrList.add(new Product(mOriginalValues.get(i).name,mOriginalValues.get(i).price));
}
}
// set the Filtered result to return
results.count = FilteredArrList.size();
results.values = FilteredArrList;
}
return results;
}
};
return filter;
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:id="#+id/etSearch"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ListView
android:id="#+id/lvProducts"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
></ListView>
</LinearLayout>
row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/llContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="#+id/tvName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_weight="1"
/>
<TextView
android:id="#+id/tvPrice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_weight="1"
/>
</LinearLayout>
Implement filterable in your customadapter class.
public class MainActivity extends AppCompatActivity {
String names[] = {"Apple","Banana","Kiwi","Oranges","Watermelon"};
String emails[] = {"This is apple","This is banana","This is kiwi","This is oranges","This is watermelon"};
int images[] = {R.drawable.apple,R.drawable.banana,R.drawable.kiwi,R.drawable.oranges,R.drawable.watermelon};
List<ItemsModel> itemsModelList = new ArrayList<>();
ListView listView;
CustomAdapter customAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.listview);
for(int i = 0;i < names.length;i++){
ItemsModel itemsModel = new ItemsModel(names[i],emails[i],images[i]);
itemsModelList.add(itemsModel);
}
customAdapter = new CustomAdapter(itemsModelList,this);
listView.setAdapter(customAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_menu,menu);
MenuItem menuItem = menu.findItem(R.id.searchView);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
Log.e("Main"," data search"+newText);
customAdapter.getFilter().filter(newText);
return true;
}
});
return true;
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
if(id == R.id.searchView){
return true;
}
return super.onOptionsItemSelected(item);
}
public class CustomAdapter extends BaseAdapter implements Filterable {
private List<ItemsModel> itemsModelsl;
private List<ItemsModel> itemsModelListFiltered;
private Context context;
public CustomAdapter(List<ItemsModel> itemsModelsl, Context context) {
this.itemsModelsl = itemsModelsl;
this.itemsModelListFiltered = itemsModelsl;
this.context = context;
}
#Override
public int getCount() {
return itemsModelListFiltered.size();
}
#Override
public Object getItem(int position) {
return itemsModelListFiltered.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = getLayoutInflater().inflate(R.layout.row_items,null);
TextView names = view.findViewById(R.id.name);
TextView emails = view.findViewById(R.id.email);
ImageView imageView = view.findViewById(R.id.images);
names.setText(itemsModelListFiltered.get(position).getName());
emails.setText(itemsModelListFiltered.get(position).getEmail());
imageView.setImageResource(itemsModelListFiltered.get(position).getImages());
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("main activity","item clicked");
startActivity(new Intent(MainActivity.this,ItemsPreviewActivity.class).putExtra("items",itemsModelListFiltered.get(position)));
}
});
return view;
}
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if(constraint == null || constraint.length() == 0){
filterResults.count = itemsModelsl.size();
filterResults.values = itemsModelsl;
}else{
List<ItemsModel> resultsModel = new ArrayList<>();
String searchStr = constraint.toString().toLowerCase();
for(ItemsModel itemsModel:itemsModelsl){
if(itemsModel.getName().contains(searchStr) || itemsModel.getEmail().contains(searchStr)){
resultsModel.add(itemsModel);
}
filterResults.count = resultsModel.size();
filterResults.values = resultsModel;
}
}
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
itemsModelListFiltered = (List<ItemsModel>) results.values;
notifyDataSetChanged();
}
};
return filter;
}
}
}
full tutorial can be found here:
listview with search and onItemClickListner
for this, you first need to add an edittext, where you will type to filter data from the list,
then enable filteration in the list,
editText = (EditText) findViewById(R.id.searchList);
adapter = new CustomListViewAdapter(this,
R.layout.list_row, rowItems);
listView.setAdapter(adapter);
listView.setTextFilterEnabled(true);
Then you need to add TextChangeListener() for the edittext,
editText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}
public void beforeTextChanged(CharSequence arg0, int arg1,
int arg2, int arg3) {
}
public void afterTextChanged(Editable arg0) {
MyActivityName.this.adapter.getFilter().filter(arg0);
}
});
You can set a TextWatcher for your search box and change your Cursor on onTextChanged() on TextWatcher like Codes below :
TextWatcher filterNameTextWatcher = new TextWatcher()
public void beforeTextChanged(CharSequence s, int start, int count,int after)
{
}
public void onTextChanged(CharSequence s,int start, int before,int count)
{
Cursor FilteredNameList = ZoneCardDBAdapter.instance.CursorFilteredName(s.toString());
Listadapter.changeCursor(FilteredNameList);
}
#Override
public void afterTextChanged(Editable arg0)
{
}
};
EditText filterTextName = (EditText)this.findViewById(R.id.edtZoneCardNameFilter);
filterTextCPName.addTextChangedListener(filterNameTextWatcher);
Use below kind of method.
your edit text box.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable theWatchedText) {
}
});
}
SearchWithMenuActivity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="match_parent"
tools:context=".SearchWithMenuActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="#layout/expand_layout"
android:id="#+id/recycler_view"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:orientation="vertical"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
search_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/app_bar_search"
android:icon="#drawable/ic_search_black_24dp"
android:title="#string/search"
app:showAsAction="ifRoom|withText"
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
</menu>
expand_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:background="?attr/selectableItemBackground"
android:elevation="6dp">
<androidx.cardview.widget.CardView
android:id="#+id/cardview"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
app:cardCornerRadius="5dp"
app:cardUseCompatPadding="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/layout_click"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/srNo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="#string/srNo"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="#+id/part_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="8dp"
android:text="#string/enter_the_name"
android:textSize="16sp"
android:textStyle="bold" />
<ImageView
android:id="#+id/arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="#string/todo"
android:padding="8dp"
android:src="#drawable/arrow_down_24" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
ExpandModel.kt
package com.materialsouk.allcodeapp.models
class ExpandModel(private var name:String,private var expanded:Boolean = false) {
fun setName(name: String) {
this.name = name
}
fun getName():String{
return name
}
fun setExpanded(expanded: Boolean) {
this.expanded = expanded
}
fun getExpanded():Boolean{
return expanded
}
}
ExpandAdapter.kt
package com.materialsouk.allcodeapp.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.materialsouk.allcodeapp.R
import java.util.ArrayList
import android.view.animation.Animation.RELATIVE_TO_SELF
import android.view.animation.RotateAnimation
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.materialsouk.allcodeapp.models.ExpandModel
class ExpandAdapter(private var expandList: ArrayList<ExpandModel>) :
RecyclerView.Adapter<ExpandAdapter.ViewHolder>() {
class ViewHolder(ItemView: View) : RecyclerView.ViewHolder(ItemView) {
val srNo: TextView = itemView.findViewById(R.id.srNo)
val nameTxt: TextView = itemView.findViewById(R.id.part_name)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view: View =
LayoutInflater.from(parent.context).inflate(R.layout.expand_layout, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.srNo.text = (position + 1).toString()
holder.nameTxt.text = expandList[position].getName()
}
override fun getItemCount(): Int {
return expandList.size
}
}
SearchWithMenuActivity.kt
package com.materialsouk.allcodeapp
import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Menu
import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.RecyclerView
import com.materialsouk.allcodeapp.adapters.ExpandAdapter
import com.materialsouk.allcodeapp.models.ExpandModel
import java.util.*
import kotlin.collections.ArrayList
class SearchWithMenuActivity : AppCompatActivity() {
private lateinit var arrayList: ArrayList<ExpandModel>
private lateinit var adapter: ExpandAdapter
private lateinit var recyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search_with_menu)
recyclerView = findViewById(R.id.recycler_view)
arrayList = ArrayList()
arrayList.add(ExpandModel("Meet", false))
arrayList.add(ExpandModel("Ankit", false))
arrayList.add(ExpandModel("Rushil", false))
arrayList.add(ExpandModel("Abhishek", false))
arrayList.add(ExpandModel("Modi", false))
arrayList.add(ExpandModel("Ghree", false))
arrayList.add(ExpandModel("Kirtan", false))
arrayList.add(ExpandModel("Ankita", false))
arrayList.add(ExpandModel("Soham", false))
arrayList.add(ExpandModel("Ganesh", false))
arrayList.add(ExpandModel("Dixit", false))
arrayList.add(ExpandModel("Ankash", false))
arrayList.add(ExpandModel("Parth", false))
arrayList.add(ExpandModel("Pranav", false))
arrayList.add(ExpandModel("Ankit Sir", false))
arrayList.add(ExpandModel("Priya Mem", false))
arrayList.add(ExpandModel("Jinal Mem", false))
arrayList.add(ExpandModel("Bhumi", false))
arrayList.add(ExpandModel("Nidhi", false))
arrayList.add(ExpandModel("Hardik", false))
arrayList.add(ExpandModel("Mayank", false))
arrayList.add(ExpandModel("Kaushik", false))
arrayList.add(ExpandModel("Rinku", false))
arrayList.add(ExpandModel("Mom", false))
adapter = ExpandAdapter(arrayList)
recyclerView.adapter = adapter
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.search_menu, menu)
val search = menu.findItem(R.id.app_bar_search)
val searchView = search.actionView as SearchView
searchView.maxWidth = android.R.attr.width
searchView.queryHint = "Search"
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
#SuppressLint("NotifyDataSetChanged")
override fun onQueryTextChange(newText: String?): Boolean {
val freeServiceModelArrayList: ArrayList<ExpandModel> = ArrayList()
for (i in arrayList) {
if (i.getName().lowercase(Locale.getDefault()).contains(
newText!!.lowercase(
Locale.getDefault()
)
)
) {
freeServiceModelArrayList.add(i)
}
}
adapter = ExpandAdapter(freeServiceModelArrayList)
recyclerView.adapter = adapter
adapter.notifyDataSetChanged()
return true
}
})
return super.onCreateOptionsMenu(menu)
}
}
I want to display a carousel like an item in the RecyclerView. I use lib CarouselView.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView list = (RecyclerView) findViewById(R.id.list);
list.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
list.setLayoutManager(layoutManager);
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < 10; i++) {
numbers.add(i);
}
final CarouselAdapter adapter = new CarouselAdapter(this, numbers);
list.setAdapter(adapter);
final SwipeRefreshLayout swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
swipeRefresh.setColorSchemeResources(R.color.green);
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
swipeRefresh.setRefreshing(false);
adapter.notifyDataSetChanged();
}
});
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/green"
android:scrollbars="vertical"/>
</android.support.v4.widget.SwipeRefreshLayout>
CarouselAdapter.java
public class CarouselAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private List<Integer> numbers;
public CarouselAdapter(Context context, List<Integer> numbers) {
this.context = context;
this.numbers= numbers;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, null);
return new CarouselViewHolder(view);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
((CarouselViewHolder) holder).carousel.setPageCount(numbers.size());
((CarouselViewHolder) holder).carousel.setViewListener(viewListener);
}
#Override
public int getItemCount() {
return numbers.size();
}
private ViewListener viewListener = new ViewListener() {
#Override
public View setViewForPosition(int position) {
TextView textView = (TextView) LayoutInflater.from(context).inflate(R.layout.item_carousel, null);
textView.setText(String.valueOf(numbers.get(position)));
return textView;
}
};
private class CarouselViewHolder extends RecyclerView.ViewHolder {
public CarouselView carousel;
private CarouselViewHolder(View itemView) {
super(itemView);
carousel = (CarouselView) itemView.findViewById(R.id.carousel);
}
}
}
item_list.xml
<?xml version="1.0" encoding="utf-8"?>
<com.synnapps.carouselview.CarouselView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/carousel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:fillColor="#color/green"/>
item_carousel.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"/>
I change CarouselViewPager from CarouselView, added next code
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
if (getChildCount() != 0) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h > height) height = h;
}
} else {
height = heightMeasureSpec;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
But when call swipe refresh and adapter update, all views in carousel disappear. I think that the problem is not called onMeasure after adapter.notifyDataSetChanged(). How I can fix it?
Before marking this as a duplicate i have tried all the solutions but nothing worked. Please go through the question and help me.
I have a recycler view that will have multiple viewPagers and both will scroll individually. I cant seem to implement this. My Code is as follows
RecyclerView Adapter
public class Adapter extends RecyclerView.Adapter<Adapter.holder> {
private final LayoutInflater mLayoutInflater;
private final Context context;
private final RecyclerView r;
private OnLoadMoreListener onLoadMoreListener;
ArrayList<ceo> mArray = new ArrayList<>();
private int heightPixels;
private int widthPixels;
MainActivity contextActivity;
public holder mh;
public Adapter(Context mContext, final RecyclerView r,MainActivity conts) {
contextActivity=conts;
this.r=r;
context = mContext;
mLayoutInflater = LayoutInflater.from(mContext);
r.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (!r.canScrollVertically(1)) {
onLoadMoreListener.onLoadMore();
}
}
});
}
public void setmArray(ArrayList<ceo> mArray) {
this.mArray = mArray;
Log.e("This->", mArray.toString());
notifyItemRangeChanged(0, mArray.size());
}
#Override
public holder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = mLayoutInflater.inflate(R.layout.recycler_custom_photo,viewGroup, false);
mh = new Adapter.holder(v);
return mh;
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
#Override
public void onBindViewHolder(holder holder, int i) {
ViewPagerAdapter mp = new ViewPagerAdapter(context,mArray);
holder.vp.setAdapter(mp);
}
#Override
public int getItemCount() {
return mArray.size();
}
class holder extends RecyclerView.ViewHolder {
ViewPager vp;
public holder(View itemView) {
super(itemView);
vp=(ViewPager)itemView.findViewById(R.id.pager);
}
}
}
View Pager Adapter
public class ViewPagerAdapter extends PagerAdapter {
ArrayList<ceo> alias=null;
private boolean tk=true;
Context mcov;
public ViewPager(Context context,ArrayList<ceo> checkAlias) {
mcov=context;
this.alias=checkAlias;
}
#Override
public int getCount() {
Log.e("Sze",alias.size()+"");
return alias.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
public void setNestedIndic(boolean token)
{
tk=token;
}
public Bitmap decodeFile(File f) {
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
//The new size we want to scale to
final int REQUIRED_SIZE = 290;
//Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE && o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
}
return null;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater mlAy = (LayoutInflater) mcov
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View m=mlAy.inflate(R.layout.custom_photo, container, false);
ImageView mimg=(ImageView)m.findViewById(R.id.mainImageFeed);
TextView tc=(TextView)m.findViewById(R.id.texr);
String path=alias.get(position).getPath();
Log.e("Pos",""+position);
tc.setText(position+" ");
container.addView(m);
return m;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
// Remove viewpager_item.xml from ViewPager
((android.support.v4.view.ViewPager) container).removeView((RelativeLayout) object);
}
}
recycler_custom_photo.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
custom_photo.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#313131"
android:id="#+id/taken"
android:layout_height="wrap_content">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/old"
android:id="#+id/mainImageFeed"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/texr"
android:textSize="40dp"
/>
</RelativeLayout>
What changes do i need to make to make these work? Thank You for answering!
The code was fine. The thing i missed out was adding a specific height to the viewpager inside the recyclerview. Also i instantiated the LayoutInflater in the constructor of the PagerAdapter and not instantiateItem. Hope this helps someone in the future!
I'm trying to take a RecyclerView with a StaggeredGridLayout and make it a fixed height by having it measure the views and set the height dynamically. I'm overriding the onMeasure(), but it does not always seem to measure correctly. I'd say it works about 50% of the time. The other 50% of the time it under measures it. I think it has to do with when the text wraps in the view_tile_small.xml, but I'm not sure.
Fragment
public class AtTheMuseumFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
//Odds n Ends Variables
private MapFragment mapFragment;
private FragmentTransaction fragmentTransaction;
private User user = new User();
private MuseumCollection museumCollection;
private Context context;
//Story Grid Adapter Variables
private AtTheMuseumAdapter nearMeAdapter;
private TileFactory tileFactory;
//Interfaces
private OnFragmentChangeListener changeListener;
#Bind(R.id.stories_list_view) RecyclerView storiesListView;
#Bind(R.id.swipe_container) SwipeRefreshLayout swipeRefreshLayout;
public static AtTheMuseumFragment newInstance(MuseumCollection museumCollection) {
AtTheMuseumFragment fragment = new AtTheMuseumFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
public AtTheMuseumFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
museumCollection = ((MainActivity) getActivity()).getMuseumCollection();
context = getActivity().getApplicationContext();
tileFactory = new TileFactory();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_museum, container, false);
ButterKnife.bind(this, view);
//Sets up the layoutManager to the Mason View
storiesListView.setLayoutManager(new MeasuredStaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
//Sets up The map
try{
fragmentTransaction = getChildFragmentManager().beginTransaction();
mapFragment = MapFragment.newInstance(MapFragment.MUSEUM);
fragmentTransaction.add(R.id.museum_map, mapFragment).commit();
}catch (Exception e){
Log.d("Map - Initial Inflate:", e.getMessage());
}
//Sets up the swipe to refresh jawn
swipeRefreshLayout.setOnRefreshListener(this);
setNearMeAdapter();
return view;
}
#Override
public void onResume(){
super.onResume();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
changeListener = (OnFragmentChangeListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
changeListener = null;
}
/**
* Loads the adapter once the data is ready
*
*/
public void setNearMeAdapter(){
List<MuseumObject> newList = museumCollection.getObjectsNearUser(User.position, 4);
List<Tile> tiles = tileFactory.createAtMuseumFeed(newList, true);
nearMeAdapter = new AtTheMuseumAdapter(context, tiles, getActivity());
storiesListView.setAdapter(nearMeAdapter);
}
/**
* Refreshes Adapter with new data
*
*/
public void refreshNearMeAdapter(){
//TODO CHANGE THIS TO LOCATION BASED WHEN TIME IS RIGHT - Peter
//nearMeAdapter.setNewData(MuseumCollection.getObjectsNearUser(User.position, 4));
List<MuseumObject> newList = museumCollection.getRandomOrder();
nearMeAdapter.setNewData(tileFactory.createAtMuseumFeed(newList,false));
}
/**
* Adds past data to the Adapter
*
*/
public void loadPastObjects(){
//TODO MAKE THIS NOT ONLY LOAD RANDOM DATA - Peter
List<MuseumObject> newList = museumCollection.getRandomOrder();
nearMeAdapter.addNewData(tileFactory.createAtMuseumFeed(newList, false));
nearMeAdapter.notifyDataSetChanged();
}
#Override
public void onRefresh() {
user.updateUserLocation();
refreshNearMeAdapter();
mapFragment.refreshMap(museumCollection.getObjectFeed());
swipeRefreshLayout.setRefreshing(false);
}
public interface OnFragmentChangeListener {
void onFragmentChange(String fragment);
}
#OnClick(R.id.explore_map)
public void exploreMap(){
changeListener.onFragmentChange("map");
}
#OnClick(R.id.load_more)
public void loadMore(){
loadPastObjects();
}
}
MeasuredStaggeredGridLayoutManager
public class MeasuredStaggeredGridLayoutManager extends StaggeredGridLayoutManager {
public MeasuredStaggeredGridLayoutManager(int spanCount, int orientation) {
super(spanCount, orientation);
}
private int[] mMeasuredDimension = new int[2];
#Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
int heightR = 0;
int heightL = 0;
for (int i = 0; i < getItemCount(); i++) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
if (getOrientation() == HORIZONTAL) {
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
if(i % 2 == 0){
heightL += mMeasuredDimension[1];
}else{
heightR += mMeasuredDimension[1];
}
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
if(heightL != 0 || heightR != 0){
height = (heightL > heightR) ? heightL : heightR;
}
//TODO come up with a better way to fix the slightly wrong height
// must be not accounting for padding or margin or something - Peter
height += (20 * (getItemCount() / 2)) + 5;
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
if (view != null) {
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
getPaddingLeft() + getPaddingRight(), p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
getPaddingTop() + getPaddingBottom(), p.height);
view.measure(childWidthSpec, childHeightSpec);
measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}
}
AtTheMuseumAdapter
public class AtTheMuseumAdapter extends RecyclerView.Adapter<AtTheMuseumAdapter.MuseumStoriesViewHolder> {
private List<Tile> tiles;
private LayoutInflater inflater;
private AdapterCallback mListener;
private Context context;
public AtTheMuseumAdapter(Context context, List<Tile> tiles, Activity activity) {
this.tiles = tiles;
this.context = context;
inflater = LayoutInflater.from(this.context);
//Sets up interface between Stock Adapter and Fragment
try {
this.mListener = ((AdapterCallback) activity);
} catch (ClassCastException e) {
throw new ClassCastException("Fragment must implement AdapterCallback.");
}
}
#Override
public MuseumStoriesViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = inflater.inflate(R.layout.view_tile_small, viewGroup, false);
MuseumStoriesViewHolder holder = new MuseumStoriesViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(MuseumStoriesViewHolder holder, int position) {
Tile currentTile = tiles.get(position);
holder.title.setText(currentTile.getTitle());
holder.desc.setText(currentTile.getDescription());
holder.type.setText(currentTile.getObjectTypeName());
//Using Picasso since it handles caching and all that jazz
Picasso.with(context)
.load(currentTile.getImg())
.into(holder.img);
}
#Override
public int getItemCount() {
return tiles.size();
}
public void setNewData(List<Tile> newItems){
tiles = newItems;
notifyDataSetChanged();
}
public void addNewData(final List<Tile> newItems){
tiles.addAll(newItems);
notifyDataSetChanged();
}
class MuseumStoriesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView type,title,desc;
public ImageView img;
public MuseumStoriesViewHolder(View itemView) {
super(itemView);
//Tried Butterknife, but it doesn't seem like it was working in the view holder. - Peter
type = (TextView) itemView.findViewById(R.id.small_box_type);
title = (TextView) itemView.findViewById(R.id.small_box_title);
desc = (TextView) itemView.findViewById(R.id.small_box_desc);
img = (ImageView) itemView.findViewById(R.id.small_box_image);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
Tile t = tiles.get(getPosition());
switch (t.getObjectTypeName()){
case Tile.OBJECT_NAME:
mListener.onObjectClick(t.getObjectID());
break;
case Tile.TOUR_NAME:
mListener.onTourCLick(t.getTourID());
break;
case Tile.STORY_NAME:
mListener.onStoryClick(t.getObjectID(), t.getStoryID());
break;
}
}
}
public interface AdapterCallback {
public void onObjectClick(String objectID);
public void onStoryClick(String objectID, String storyID);
public void onTourCLick(String tourID);
}
}
view_tile_small.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin_small"
android:background="#color/small_box_background_color">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--TODO Make layout_height wrap contenet -->
<ImageView
android:id="#+id/small_box_image"
android:layout_width="match_parent"
android:layout_height="150dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:maxHeight="150dp"
android:background="#color/transparent"/>
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="right"
android:src="#drawable/abc_btn_rating_star_off_mtrl_alpha"
/>
<TextView
android:id="#+id/small_box_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_normal"
android:paddingBottom="#dimen/margin_normal"
android:textSize="#dimen/font_small"
android:textColor="#color/font_white"
android:background="#drawable/small_box_text_bottom_border"
android:layout_gravity="bottom"
android:text="Object Story"
/>
</FrameLayout>
<TextView
android:id="#+id/small_box_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/margin_larger"
android:layout_marginBottom="#dimen/margin_normal"
android:layout_marginRight="#dimen/margin_larger"
android:layout_marginTop="#dimen/margin_larger"
android:textSize="#dimen/font_large"
android:textColor="#color/font_black"
android:text="Sample Text Here"
/>
<TextView
android:id="#+id/small_box_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/margin_larger"
android:layout_marginBottom="#dimen/margin_larger"
android:textSize="#dimen/font_normal"
android:textColor="#color/font_black"
android:textStyle="italic"
android:text="Sample Text Here"
/>
</LinearLayout>
fragment_museum
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.bluecadet.android.nasm.ui.AtTheMuseumFragment"
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="100dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:descendantFocusability="blocksDescendants"
>
<TextView
android:id="#+id/museum_header"
style="#style/header"
android:text="#string/museum_header"
android:layout_margin="#dimen/margin_larger"
android:elevation="8dp"
/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="275dp"
android:elevation="2dp"
>
<FrameLayout
android:id="#+id/museum_map"
android:layout_height="fill_parent"
android:layout_width="match_parent"
/>
<include
layout="#layout/view_explore_map" />
</FrameLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/stories_list_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/margin_normal"
android:layout_marginLeft="#dimen/margin_small"
android:layout_marginRight="#dimen/margin_small"
android:layout_marginTop="#dimen/margin_normal"
android:stretchMode="columnWidth"
/>
<Button
android:id="#+id/load_more"
style="#style/home_button"
android:gravity="center"
android:text="#string/button_load_more"
/>
</LinearLayout>
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
ViewTreeObserver code I'm playing with now. It's in Fragment.
mTopStoriesListView.setLayoutManager(new NewMeasuredStaggeredLayoutManager(2, StaggeredGridLayoutManager.VERTICAL, mTopStoriesListView));
mTopStoriesListView.setNestedScrollingEnabled(false);
//Testing Issue 54
final ViewTreeObserver viewTreeObserver = mTopStoriesListView.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mTopStoriesListView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int l = 0,r = 0;
for(int i = 0 ; i < mNearMeAdapter.getItemCount(); i++){
int h = mTopStoriesListView.getLayoutManager().findViewByPosition(i).getHeight();
ViewGroup.MarginLayoutParams layout = (ViewGroup.MarginLayoutParams) mTopStoriesListView.getLayoutManager()
.findViewByPosition(i).getLayoutParams();
int t = layout.topMargin;
int b = layout.bottomMargin;
if(i % 2 == 0){
l += h + t + b;
}else{
r += h + t + b;
}
}
int viewHeight = (l > r) ? l : r;
mTopStoriesListView.getLayoutParams().height = viewHeight;
Log.d("TAG", String.valueOf(viewHeight));
}
});
}
//END TEST
Have you look at ViewTreeObserver ?
I got a similar problem on a passed project and I have found it more reliable than onMesure to dynamically get Layout properties
You can go through it from here : http://developer.android.com/reference/android/view/ViewTreeObserver.html