Android : Set center position item of a RecyclerView - android

I want to implement a view picker which is like a number view picker but instead of picking numbers, it will pick the view in the center of the picker.
The basic idea is to get the position of centered item and replace the view at that position with a different view. To do so, I have done following -
I have the following layout -
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<View
android:id="#+id/view"
android:background="#ffeb3b"
android:layout_gravity="center"
android:layout_height="56dp"
android:layout_width="match_parent" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rvItems"
android:clipToPadding="false"
android:layout_height="match_parent"
android:layout_width="match_parent" />
</FrameLayout>
The activity for populating view is -
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private RecyclerView rvItems;
private View view;
private List<Data> array = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int i=0; i< 100; i++) {
final Data data = new Data();
data.isVisible = true;
data.data = String.valueOf(i);
array.add(data);
}
view = (View) findViewById(R.id.view);
rvItems = (RecyclerView) findViewById(R.id.rvItems);
rvItems.setAdapter(new SliderAdapter(array));
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
rvItems.setLayoutManager(layoutManager);
rvItems.post(new Runnable() {
#Override
public void run() {
int firstVisibleChildPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
int lastVisibleChildPosition = layoutManager.findLastCompletelyVisibleItemPosition();
int centerChildPosition = (firstVisibleChildPosition + lastVisibleChildPosition) / 2;
for (int i=0; i < centerChildPosition; i++) {
final Data data = new Data();
data.isVisible = false;
// Adding empty list at begining and end of position
array.add(0, data);
array.add(array.size(), data);
}
rvItems.getAdapter().notifyDataSetChanged();
}
});
rvItems.addOnScrollListener(new RecyclerView.OnScrollListener() {
int centerChildPosition = -1;
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
int firstVisibleChildPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
int lastVisibleChildPosition = layoutManager.findLastCompletelyVisibleItemPosition();
centerChildPosition = (firstVisibleChildPosition + lastVisibleChildPosition) / 2;
recyclerView.scrollToPosition(centerChildPosition);
}
Log.d(TAG, "center position = " + centerChildPosition );
}
});
}
}
Using the above code, I am able to know the centered child position but not able to fit it properly inside the yellow rectangle view -
How can I make sure that the numbers are within yellow bar? For now, I have added empty views on the top and bottom of the list so that the first and last items in the list can be centered. What is an optimum way to do it?

Related

How to update ListView entries and let the user continue and scrolling the listview values?

I am trying to update the list of listView while the user is scrolling the list and give the user the option to continue and scrolling the new entries but with no success and i need an help.
In my application, i have a chat and i am saving history of the chat at SQLite. when the user is entered to the chat, the application is reading only the last 25 message and present the newest message at the bottom of the list.
In order that do that i am using the following options at the XML:
android:transcriptMode="alwaysScroll"
android:stackFromBottom="true"
and it is working fine.
Now , when the user is starting to scroll up and checking the history of the chat, when he is arriving to the top of the list, i am accessing the database and retrieving another 25 messages and add them to the top of the list and i am calling to:
chatAdaptor.notifyDataSetChanged();
but when the user is trying to scroll up, nothing is presented, only after scrolling down and up again the new entries are presented.
I have try to set the position of the list view using setSelection and smoothScrollToPosition but it is not really work.
how can it update the list with new entries and give the user the option to continue and scroll up?
here is the relevant code:
<ListView
android:id="#+id/chatList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:layout_margin="2dp"
android:layout_weight="1"
android:transcriptMode="alwaysScroll"
android:stackFromBottom="true"
android:background="#drawable/frame_tab"></ListView>
public void showChatLines() {
chatLinesView = chatTextDialog.findViewById(R.id.chatList);
chatAdaptor = new GenericAdapter<ChatLine>(activity, chatLines) {
#Override
public View getMyView(int position, View convertView, ViewGroup parent, ChatLine chatLine) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.chat_line, null);
TextView chatLineText = view.findViewById(R.id.chatLine);
chatLineText.setText(chatLine.messageText);
TextView chatLineTime = view.findViewById(R.id.chatLineTime);
chatLineTime.setText(chatLine.displayDateTime);
TextView chatLineUserName = view.findViewById(R.id.userName);
chatLineUserName.setText(chatLine.userDisplayName);
chatLineUserName.setTextColor(activity.getColor(Constants.colors[getColorBy(chatLine.userName)]));
LinearLayout chatLineLayout = view.findViewById(R.id.chatLineLayout);
LinearLayout.LayoutParams chatLineLayoutParams = (LinearLayout.LayoutParams) chatLineLayout.getLayoutParams();
CardView chatLineBackground = view.findViewById(R.id.chatLineBackground);
LinearLayout.LayoutParams chatLineBackgroundParams = (LinearLayout.LayoutParams) chatLineBackground.getLayoutParams();
LinearLayout chatLineSubLayout = view.findViewById(R.id.chatLineSubLayout);
FrameLayout.LayoutParams chatLineSubLayoutParams = (FrameLayout.LayoutParams) chatLineSubLayout.getLayoutParams();
if (chatLine.userName.equals(logonUserName)) {
CardView charLineCard = view.findViewById(R.id.chatLineBackground);
charLineCard.setCardBackgroundColor(activity.getColor(R.color.focusedColor));
((ViewGroup) chatLineUserName.getParent()).removeView(chatLineUserName);
} else {
chatLineLayoutParams.gravity = Gravity.RIGHT;
chatLineLayout.setLayoutParams(chatLineLayoutParams);
chatLineSubLayoutParams.gravity = Gravity.RIGHT;
chatLineSubLayout.setLayoutParams(chatLineSubLayoutParams);
chatLineBackgroundParams.gravity = Gravity.RIGHT;
chatLineBackground.setLayoutParams(chatLineBackgroundParams);
}
if (position==0 & fromLine!=0) {
getNextChatLinesFromDb(position);
}
return view;
}
};
chatLinesView.setAdapter(chatAdaptor);
}
private void getNextChatLinesFromDb(int position) {
toLine = fromLine - 1;
fromLine -= pageSize;
if (fromLine < 0) {
fromLine = 0;
}
ArrayList<ChatLine> newChatLines = db.getChatLines(chatRoomId, fromLine, toLine);
chatLines.addAll(0, newChatLines);
chatAdaptor.notifyDataSetChanged();
}
Try below sample code:
activity_main.xml
<?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="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ListView
android:id="#+id/listView"
android:transcriptMode="alwaysScroll"
android:stackFromBottom="true"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity implements AbsListView.OnScrollListener{
final static private int ADD_DATA_SIZE = 10;
ArrayList<String> dataList;
ListView listView;
ArrayAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataList = new ArrayList<>();
for(int i=0; i<30; i++){
dataList.add("Item " + i);
}
listView = findViewById(R.id.listView);
adapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, dataList);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(getApplicationContext(), adapterView.getItemAtPosition(i) + " Clicked!", Toast.LENGTH_SHORT).show();
}
});
listView.setOnScrollListener(this);
}
private void addNewData() {
ArrayList<String> tmpList = new ArrayList<>();
for(int i=0; i<ADD_DATA_SIZE; i++){
tmpList.add("Add " + (dataList.size() - 20)/10 + ": Item " + i);
}
dataList.addAll(0, tmpList);
// Try this:
//listView.setSelection(ADD_DATA_SIZE);
//adapter.notifyDataSetInvalidated();
// or this:
adapter.notifyDataSetChanged();
listView.setSelection(ADD_DATA_SIZE);
}
#Override
public void onScrollStateChanged(AbsListView absListView, int i) {}
#Override
public void onScroll(AbsListView absListView, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(firstVisibleItem == 0){
View view = absListView.getChildAt(0);
if(view != null){
if (view.getTop() == absListView.getTop()) {
absListView.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_DISABLED);
Toast.makeText(getApplicationContext(), "TRANSCRIPT MODE CHANGED TO: "
+ absListView.getTranscriptMode(), Toast.LENGTH_SHORT).show();
addNewData();
}
}
} else if (totalItemCount == (firstVisibleItem + visibleItemCount)){
View view = absListView.getChildAt(visibleItemCount - 1);
if (view.getBottom() == absListView.getBottom()) {
absListView.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
Toast.makeText(getApplicationContext(), "TRANSCRIPT MODE CHANGED TO: "
+ absListView.getTranscriptMode(), Toast.LENGTH_SHORT).show();
}
}
}
}
Hope it helps!
i think this code will help you :
// get position of listview
int index = chatLinesView.getFirstVisiblePosition();
View v = chatLinesView.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
// notify dataset changed or re-assign adapter here
//re-assign the position of listview after setting the adapter again
chatLinesView.setSelectionFromTop(index, top);
edit
int h1 = chatLinesView.getHeight();
int h2 = chatLinesViewRow.getHeight();
chatLinesView.smoothScrollToPositionFromTop(position, h1/2 - h2/2, duration);
Parameters
position -> Position to scroll to
offset ---->Desired distance in pixels of position from the top of the
view when scrolling is finished
duration-> Number of milliseconds to use for the scroll

How to add a variable number of TextViews and EditViews in activity

I'm currently trying to add a user-defined number of TextViews and EditText to an activity, but can't seem to do it other than hard-coding it by creating a variety of different activities.
The objective of this activity is to take the names of the players, the number of which is relayed by the intent extra from the preceding activity.
I'm trying to add both a TextView saying "Player X: " and an EditText to type the name of the player for each player
I know from this post: How to create a variable number of textviews in android that I have to do this programmatically, however, it does not seem to work for me (the activity remains blank when tested)
I have tried creating a temp LinearLayout to which I add the two views in a for(), still nothing.
Any ideas? Am I on the right track?
Best regards
[EDIT] Code is here :
public class players extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_players);
Bundle extras = new Bundle();
final int numPlayers = extras.getInt("num");
final LinearLayout myLayout = findViewById(R.id.lin_Re);
final ArrayList<Player> players = new ArrayList<>();
int size = numPlayers; // total number of TextViews to add
TextView[] tv = new TextView[size];
TextView temp;
EditText[] et = new EditText[size];
EditText temp2;
LinearLayout temp3;
for (int i = 0; i < size; i++)
{
temp = new TextView(this);
temp2 = new EditText(this);
temp3 = new LinearLayout(this);
temp.setText("Player " + i + " : "); //arbitrary task
// add the textview to the linearlayout
temp3.addView(temp);
temp3.addView(temp2);
tv[i] = temp;
et[i] = temp2;
myLayout.addView(temp3);
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:id="#+id/lin_Re">
</LinearLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/b_send"/>
</LinearLayout>
There is 2 way to achieve this:
1. Use a RecyclerView [Recommended]
2. Add TextView and EditText ( which is nested in a Horizontal LinearLayout) into a Vertical LinearLayout nested in a ScrollView programmatically
The first solution I describe below is quite simple if you're familiar with RecyclerView or ListView, the second solution (your current track) is a bit tricky but still achievable.
Solution 1:
MainActivity
public class MainActivity extends AppCompatActivity {
RecyclerView mPlayerList;
List<String> mPlayerNames;
PlayerAdapter mAdapter;
EditText mInput;
Button mCreateButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPlayerNames = new ArrayList<>();
// setup recycler view
mPlayerList = findViewById(R.id.player_list);
mPlayerList.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new PlayerAdapter();
mPlayerList.setAdapter(mAdapter);
// setup input EditText
mInput = findViewById(R.id.input);
// setup Create button
mCreateButton = findViewById(R.id.create_button);
mCreateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// clear old player names
mPlayerNames.clear();
// read user input: number of player:
String input = mInput.getText().toString();
int numberOfPlayer;
try {
numberOfPlayer = Integer.parseInt(input);
} catch (NumberFormatException e) {
Toast.makeText(MainActivity.this, "Invalid input!!!", Toast.LENGTH_SHORT).show();
return;
}
for (int i = 0; i < numberOfPlayer; ++i) {
mPlayerNames.add("Player #" + (i + 1));
}
// make change on recycler view
mAdapter.notifyDataSetChanged();
// dismiss keyboard
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
}
});
}
private class PlayerAdapter extends RecyclerView.Adapter<PlayerAdapter.PlayerHolder> {
#Override
public PlayerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_layout, parent, false);
return new PlayerHolder(v);
}
#Override
public void onBindViewHolder(PlayerHolder holder, int position) {
holder.bind(mPlayerNames.get(position));
}
#Override
public int getItemCount() {
return mPlayerNames.size();
}
public class PlayerHolder extends RecyclerView.ViewHolder {
TextView mPlayerLabel;
EditText mPlayerName;
public PlayerHolder(View itemView) {
super(itemView);
mPlayerLabel = itemView.findViewById(R.id.player_label);
mPlayerName = itemView.findViewById(R.id.player_name);
}
public void bind(String playerName) {
mPlayerLabel.setText(playerName);
mPlayerName.setHint("Name of " + playerName);
}
}
}
}
The sample project can be found here:
https://github.com/raiytu4/stackcase004

How to show exactly ten rows in RecyclerView

I would like to always display exactly ten rows in a RecyclerView. RecyclerView does not have a configurable setting for this. One approach is to calculate the size of each row. I would like the table to take up half the screen and always show 0..10 items within that area. If more than 10 items the user would scrooll to see the items. Right now the default behavior of RecyclerView seems to be to keep pushing everything down as it grows.
#Override
public int getItemCount() {
if(list.size()>10){
return 10;
}else{
return list.size();
}
}
In your recycler view adapter class return get item count to 10 if size of array or list is greater than 10
Your guess is right it's working with a dynamic computation of row height, here is an example:
Simple class standing for data you want to display:
public class CustomItem {
private int counter;
public CustomItem(int counter) {
this.counter = counter;
}
public int getCounter() {
return counter;
}
public void setCounter(int counter) {
this.counter = counter;
}
}
And simple layout to display CustomItem in a list:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/darker_gray">
<TextView
android:id="#+id/txvTest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="Test"/>
</RelativeLayout>
RecyclerAdapter for this class, you will see that we set row height programmatically in onBindViewHolder method:
public class CustomItemRecyclerAdapter extends RecyclerView.Adapter<CustomItemRecyclerAdapter.SimpleItemViewHolder> {
private static int NB_OF_ITEM_TO_DISPLAY = 10;
private List<CustomItem> customItems;
private Context context;
private int rowHeight;
public class SimpleItemViewHolder extends RecyclerView.ViewHolder {
TextView txvTest;
RelativeLayout container;
public SimpleItemViewHolder(View itemView) {
super(itemView);
txvTest = (TextView) itemView.findViewById(R.id.txvTest);
container = (RelativeLayout) itemView;
}
}
public CustomItemRecyclerAdapter(Context context, List<CustomItem> customItems) {
this.context = context;
this.customItems = customItems;
}
public void setItemHeight(int parentHeightInPx){
// Height of a row is just parent height divided by number of row to display
this.rowHeight = parentHeightInPx / CustomItemRecyclerAdapter.NB_OF_ITEM_TO_DISPLAY;
// Notify adapter because items will need to be redraw to use newly set height
this.notifyDataSetChanged();
}
#Override
public SimpleItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.custom_item, parent, false);
return new SimpleItemViewHolder(itemView);
}
#Override
public void onBindViewHolder(SimpleItemViewHolder holder, int position) {
CustomItem item = customItems.get(position);
holder.txvTest.setText("Item " + item.getCounter());
holder.txvTest.setBackgroundColor(item.getCounter());
// Row size magic is here!
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, rowHeight);
holder.container.setLayoutParams(params);
}
#Override
public int getItemCount() {
return customItems.size();
}
}
Activity layout, with both a TextView used as placeholder for half the screen and the RecyclerView:
<?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">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#color/colorAccent"
android:text="TEST"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/a_main_rcv_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:layout_weight="1"
android:scrollbars="vertical"/>
</LinearLayout>
And Activity code with comments to understand how it works ;):
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private CustomItemRecyclerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Link to layout recycler view
recyclerView = (RecyclerView) findViewById(R.id.a_main_rcv_items);
// Create a simple linear layout manager and set it to recyclerview
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
// Create an instance of our custom Adapter
adapter = new CustomItemRecyclerAdapter(MainActivity.this, generateItems(20));
// Set this adapter
recyclerView.setAdapter(adapter);
// Listen for recycler view layout change event to get its height and then compute and set new rows height
recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
// Set item height using height of recyclerView
adapter.setItemHeight(view.getHeight());
// Need to simulate a scroll to force a redraw of recycler rows with new height... I have not find better for now...
recyclerView.scrollBy(0,1);
}
});
}
private List<CustomItem> generateItems(int nb) {
ArrayList<CustomItem> items = new ArrayList<>(nb);
for (int i = 1; i < nb + 1; i++) {
items.add(new CustomItem(i));
}
return items;
}
}

Android RecyclerView DefaultItemAnimator - Items moving weirdly

I have a problem with a simple multicolumn layout RecyclerView which is best reproducible on tablets. I have created a basic example with fully functional source code below, maybe it is easier to quickly run it, instead of trying to understand what I mean ;)
The main problem on tablets (where I have a grid layout) is, that items get strangely rearranged when hiding specific items and displaying them again (via notifyItemRemoved() and notifyItemInserted()). I think this can be even reproduced with removing and inserting only the first item. The layout manager inserts an extra row at the top and moves items from the first line below to fill it. (The example below removes and inserts every third item, starting with the first one)
I have different types of items (in the example red, green and blue items) and I want to toggle a specific type of items (in the example you can toggle the red items with a click on the FloatingActionButton).
The weird behavior that I want to fix can be reproduced by just clicking the FAB twice without scrolling before. This would first filter the red items and then display them again. When toggling the filter the second time you will notice that there is a row of items inserted above and items from the first row are moved to fill it.
If you didn't notice during the animation, just scroll up after toggling the filter.
I would expect that the first row stays where it is and that just the red items get displayed again.
Does anybody know how to fix that?
Here is the activity code:
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private TestAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
((FloatingActionButton) findViewById(R.id.fab)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
toggleFiltered();
}
});
final int columnCount = getColumnCount(300);
GridLayoutManager layoutManager = new GridLayoutManager(this, columnCount);
recyclerView.setLayoutManager(layoutManager);
adapter = new TestAdapter();
recyclerView.setAdapter(adapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
private void toggleFiltered() {
final boolean filtered = adapter.isFiltered();
adapter.setFiltered(!filtered);
if(filtered) {
adapter.notifyItemInserted(0);
adapter.notifyItemInserted(3);
adapter.notifyItemInserted(6);
adapter.notifyItemInserted(9);
adapter.notifyItemInserted(12);
} else {
adapter.notifyItemRemoved(0);
adapter.notifyItemRemoved(3);
adapter.notifyItemRemoved(6);
adapter.notifyItemRemoved(9);
adapter.notifyItemRemoved(12);
}
}
int getColumnCount(final int dpThreshold){
final Display display = getWindowManager().getDefaultDisplay();
final DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
final float density = getResources().getDisplayMetrics().density;
final float dpWidth = outMetrics.widthPixels / density;
return ((int) dpWidth) / dpThreshold;
}
class TestAdapter extends RecyclerView.Adapter {
public static final int TYPE_RED = 0;
public static final int TYPE_GREEN = 1;
public static final int TYPE_BLUE = 2;
private boolean filtered = false;
public boolean isFiltered() {
return filtered;
}
public void setFiltered(final boolean filtered) {
this.filtered = filtered;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
final View view = new View(parent.getContext());
view.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 500));
int color = Color.RED;
if(viewType == TYPE_GREEN){
color = Color.GREEN;
} else if (viewType == TYPE_BLUE){
color = Color.BLUE;
}
return new TestViewHolder(view, color);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
}
#Override
public int getItemViewType(final int position) {
if(!filtered) {
if ((position + 3) % 3 == 0) {
return TYPE_RED;
}
if ((position + 2) % 3 == 0) {
return TYPE_GREEN;
}
} else {
if ((position) % 2 == 0) {
return TYPE_GREEN;
}
}
return TYPE_BLUE;
}
#Override
public int getItemCount() {
if(filtered) {
return 10;
}
return 15;
}
class TestViewHolder extends RecyclerView.ViewHolder {
public TestViewHolder(final View itemView, final int color) {
super(itemView);
itemView.setBackgroundColor(color);
}
}
}
}
And here is the layout code:
<android.support.constraint.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:id="#+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="#+id/root_layout"
app:layout_constraintLeft_toLeftOf="#+id/root_layout"
app:layout_constraintRight_toRightOf="#+id/root_layout"
app:layout_constraintTop_toTopOf="#+id/root_layout"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#+id/root_layout"
app:layout_constraintRight_toRightOf="#+id/root_layout"
android:layout_margin="16dp"
/>
</android.support.constraint.ConstraintLayout>
Firstly, I should mention that the problem is not in DefaultItemAnimator. If you set your animator to null, you would have the same behavior. And actually there is no problem at all. The behavior is expected, as you're just inserting the item into the first position of your TestAdapter, and then other items are shifting, but your RecyclerView is staying at the same position.
So all you need is just add recyclerView.scrollToPosition(0); line in the end of your toggleFiltered() method, so it will scroll up, once you've applied the filtering. And it will work as you wish.
its not weird. because you notifyItemInserted(0). it is insert Item. not notifyDataSetChanged(). adapter is showing item keep going. its Green Item. you notifyItemInserted(0) insert Red, still adapter showing first item is Green(it poisition is 1). because adapter notifyItemInserted(0) has before showing first item is Green.

In an android ListView, how can I iterate/manipulate all the child views, not just the visible ones?

The code below does NOT change the text of all of a ListView's rows because getChildCount() does not get all of a ListView's rows, but just the rows that are visible.
for (int i = 0; i < listView.getChildCount(); i++)
{
View v = listView.getChildAt(i);
TextView tx = (TextView) v.findViewById(R.id.mytext);
tx.setTextSize(newTextSize);
}
So, what SHOULD I do?
Is there code for getting a notification when a ListView's row becomes visible, so I can set its text size then?
In a ListView the only children are the visible ones. If you want to do something with "all the children," do it in the adapter. That's the best place.
List13 from the API Demos does something similar using OnScrollStateChanged. There may be a better way, though:
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
mBusy = false;
int first = view.getFirstVisiblePosition();
int count = view.getChildCount();
for (int i=0; i<count; i++) {
TextView t = (TextView)view.getChildAt(i);
if (t.getTag() != null) {
t.setText(mStrings[first + i]);
t.setTag(null);
}
}
mStatus.setText("Idle");
break;
.
.
.
EDIT BY Corey Trager:
The above definitely pointed me in the right direction. I found handling OnScrollListener.onScroll worked better than onScrollStateChanged. Even if I removed the case statement in onScrollSgtaetChanged and handled every state change, some text wasn't getting resized. But with onScroll, things seem to work.
So, my seemingly working code looks like this:
public void onScroll(AbsListView v, int firstVisibleItem, int visibleCount, int totalItemCount)
{
ListView lv = this.getListView();
int childCount = lv.getChildCount();
for (int i = 0; i < childCount; i++)
{
View v = lv.getChildAt(i);
TextView tx = (TextView) v.findViewById(R.id.mytext);
tx.setTextSize(textSize);
}
}
Not so sure about the performace effect but u can try this.
//declare the list
ListView list = (ListView)findViewById(R.id.yourListID);
// in my case i have spinners and made a test just to know if this works
Spinner spnWhatever;
View view;
int i =0;
do{
view =list.getAdapter().getView(i,null,null);
//get the spinners from each row
spnWhatever =(Spinner)view.findViewById(R.id.spnTarifas);
i++;
}while(list.getAdapter().getCount() !=i);
//Create layout file containing views you want to read input from
//layout/gen_edt_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parLay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/edtGName"
android:layout_width = "match_parent"
android:layout_height ="wrap_content"
android:hint="Name"
android:inputType="text" />
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/edtGIdPass"
style="#style/edt"
android:hint="Id number"
android:inputType="number" />
</LinearLayout>
//Create Empty Activity -> MultipleInput
//layout/activity_multiple_input.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=".OpenAccount">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ListView
android:id="#+id/inputLView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="60dp" />
</LinearLayout>
<Button
android:layout_width="wrap_content
android:layout_height="wrap_content"
android:text="Read"
android:onClick="readInput"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent>
</androidx.constraintlayout.widget.ConstraintLayout>
public class MultipleInput extends AppCompatActivity {
//Declare and intialize arrays to store input fields as public modifiers
ArrayList<TextInputEditText> edtNameArr = new ArrayList<>();
ArrayList<TextInputEditText> edtIdsArr = new ArrayList<>();
//Intialize arrays to store input values as public modifiers
ArrayList<String> arr0 = new ArrayList<>();
ArrayList<String> arr1 = new ArrayList<>();
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
listView = findViewById(R.id.listView);
edtNameArr.clear();
edtIdsArr.clear();
arr0.clear();
arr1.clear();
//set number of group fields to be generated
int members = 4;
//initialize class passing fields number and context
edtAdapter = new EdtAdapter(members, getApplicationContext());
//Set retured fields in listView
listView.setAdapter(edtAdapter);
}
public class EdtAdapter extends BaseAdapter {
class ViewHolder {
TextInputEditText edtGName, edtGIdPass;
}
public Context context;
ArrayList<EdtClass> edtArrayList;
int members;
EdtAdapter(int members, Context context) {
this.members = members;
this.context = context;
}
#Override
public int getCount() {
return members;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View contentView, ViewGroup parent) {
View rowView = contentView;
if (rowView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = getLayoutInflater();
rowView = inflater.inflate(R.layout.gen_edt_layout, parent, false);
viewHolder.edtGName = rowView.findViewById(R.id.edtGName);
viewHolder.edtGIdPass = rowView.findViewById(R.id.edtGIdPass);
viewPosition = position;
//loop adding input fields in arrays
for (int i = 0; i < members; i++) {
edtNameArr.add(viewHolder.edtGName);
edtIdsArr.add(viewHolder.edtGIdPass);
}
} else {
viewHolder = (ViewHolder) contentView.getTag();
}
return rowView;
}
}
//Read input when button clicked
public void readInput(View view){
for(int edt = 0; edt<edtNameArr.size(); edt++){
String name = Objects.requireNonNull(edtNameArr.get(edt).getText()).toString();
if(!arr0.contains(name)) {
arr0.add(name);
}
String ids = Objects.requireNonNull(edtIdsArr.get(edt).getText()).toString();
if(!arr1.contains(ids)) {
arr1.add(ids);
}
}
StringBuilder name = new StringBuilder();
StringBuilder idno = new StringBuilder();
//loop through arrays with input, reading and appending values in StringBuilder
for (int m = 0; m < arr0.size(); m++) {
name.append(arr0.get(m)).append(",");
idno.append(arr1.get(m)).append(",");
}
//Show input values in logcat/Toast
Log.e("Names ", name.toString());
Log.e("Ids ", idno.toString());
Toast.makeText(MultipleInput.this, "Names "+ name.toString(), Toast.LENGTH_LONG).show();
}

Categories

Resources