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
Related
Trying to replace spinner with buttons dynamically populated from database.
Normally spinner use array adapter and built-in List Item Layouts "android.R.layout.simple_spinner_item"etc.
How should it be modified if instead of spinner you want to populate buttons?
Should I replace layouts for spinner in my in loadDifficulties() method with layouts for buttons?
HERE HOW IT WORKED WITH SPINNER
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_starting_screen);
spinnerDifficulty = findViewById(R.id.spinner_quizlist);
loadDifficulties();
Button startTest = findViewById(R.id.start_test);
startTest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startQuiz();
}
});
}
private void startQuiz() {
ListQuiz selectedLevel = (ListQuiz) spinnerDifficulty.getSelectedItem();
int LevelListID = selectedLevel.getId();
String quizListName = selectedLevel.getName();
Intent intent = new Intent(StartingScreenActivity.this, MainActivity.class);
intent.putExtra(EXTRA_DIFFICULTY_ID, LevelListID);
intent.putExtra(EXTRA_DIFFICULTY_NAME, quizListName);
startActivityForResult(intent, REQUEST_CODE_QUIZ);
}
private void loadDifficulties(){
QuizDbHelper dbHelper = QuizDbHelper.getInstance(this);
List<ListQuiz> LevelList = dbHelper.getAllListQuiz();
ArrayAdapter<ListQuiz> adapterLevelList = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, LevelList); adapterLevelList.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerDifficulty.setAdapter(adapterLevelList);
}
onCreate(){
LinearLayout listOrders = findViewById(R.id.listOrders);
for (int i = 0; i < listForShowing.size(); i++){
String text = listForShowing.get(i);
listOrders.addView(createButton(text));
}
listOrders.requestLayout();
}
public Button createButton(String text){
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Button button = inflater.inflate(R.layout.button, null);
button.setText(text);
}
Briefly
Created LinearLayout for buttons.
I didn't need to use ArrayAdapter in the loadDifficulties anymore.
Added all needed parameters to startQuiz() (in my case int & String) simplifying method to Intents only.
private ArrayAdapter <ListQuiz> adapter;
private Button autobutton;
public int categorySize;
private List<ListQuiz> categoryName;
private LinearLayout QuizListLayout;
private Button levelButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_starting_screen);
autobutton = findViewById(R.id.autobutton);
loadDifficulties();
QuizListLayout = findViewById(R.id.layoutForButtons);
for(int i=0; i<categorySize;i++){
levelButton =new Button(this);
levelButton.setText("" + categoryName.get(i));
levelButton.setId(i);
final int index = i;
levelButton.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
levelButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startQuiz(v.getId(), categoryName.get(index).toString());
}
});
QuizListLayout.addView(levelButton);
}
}
private void startQuiz(int LevelListID, String quizListName) {
Intent intent = new Intent(StartingScreenActivity.this, MainActivity.class);
intent.putExtra(EXTRA_DIFFICULTY_ID, LevelListID);
intent.putExtra(EXTRA_DIFFICULTY_NAME, quizListName);
startActivityForResult(intent, REQUEST_CODE_QUIZ);
}
private void loadDifficulties(){
QuizDbHelper dbHelper = QuizDbHelper.getInstance(this);
List<ListQuiz> LevelList = dbHelper.getAllListQuiz();
categorySize = dbHelper.getAllListQuiz().size();
categoryName = dbHelper.getAllListQuiz();
buttonlayout.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="match_parent"
android:orientation="vertical"
android:id="#+id/layoutForButtons">
</LinearLayout>
I want to display each item that is clicked into a different textView. I have each click displaying in the same textView now but i would like on each click for the data to be displayed in a new textView. Any Ideas? here is what i have so far:
ExercisesListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
private String result;
TextView Exercise1TextView = (TextView) findViewById(R.id.Exercise1TextView);
TextView Exercise2TextView = (TextView) findViewById(R.id.Exercise2TextView);
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String Exercise = String.valueOf(adapterView.getItemAtPosition(i));
result = (Exercise1TextView.getText().toString() + "\n" + Exercise);
Exercise1TextView.setText(result);
}
});
The answer to your question is very simple, you will need to create new TextViews dynamically and setText to them. This is how you should proceed. Add a linearlayout in your main layout above or below your listview where ever you desire, just like below.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/main_layout"
/>
In your Activity initialize this linearlayout
public class MainActivity extends Activity {
private LinearLayout mainLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(....);
setContentView(....);
this.mainLayout = (LinearLayout) findViewById(R.id.main_layout);
}
}
Now in your onItemClick do like this.
TextView tv = new TextView(getApplicationContext());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
tv.setTextColor(Color.BLACK);
tv.setText(result);
mainLayout.addView(tv, params);
Create an array of TextViews like that:
View[] myViews = {textView1, textView2, ....};
And call them inside onItemClick()
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
k = myViews.length < i ? myViews.length -1 : i; //or use your logic
String Exercise = String.valueOf(adapterView.getItemAtPosition(i));
result = (Exercise1TextView.getText().toString() + "\n" + Exercise);
myViews[k].setText(result);
}
I am trying to figure out how to create a breadcrumb in my android app's (material design) toolbar.
This can be seen in the latest Dropbox android application, in which the breadcrumb is used to display the navigation of the files.
I have also found an image (which I took from another similar question), which can be seen here:
Can you guide me on how I can do this?
I created a working example of this for an app, thought I would share because it became more confusing than it needed to be lol. Maybe it could save some devs a lot of effort that should not be needed :)
Add a HorizontalScrollView to your AppBarLayout (layout/examplebreadcrumbs_layout)
<android.support.v7.widget.AppBarLayout
android:id="#+id/app_bar"
style="#style/HeaderBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorPrimary"
android:minHeight="?attr/actionBarSize"
app:contentInsetStart="72dp"
app:navigationContentDescription="up" />
<HorizontalScrollView android:id="#+id/breadcrumb_wrapper"
android:layout_width="match_parent"
android:layout_height="50dp"
android:scrollbars="none">
<LinearLayout android:id="#+id/breadcrumbs"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingEnd="#dimen/activity_horizontal_margin_2"
android:paddingStart="#dimen/activity_horizontal_margin_2"/>
</HorizontalScrollView>
</android.support.v7.widget.AppBarLayout>
Create a LinearLayout that will be used for each 'breadcrumb'. You will inflate the same layout for each. (layout/breadcrumb_text)
<LinearLayout android:id="#+id/crumb"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="#+id/crumb_arrow"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:visibility="gone"
android:gravity="center_vertical"
android:text="#string/greater_than"
android:padding="4dp"
android:fontFamily="sans-serif-condensed"
android:textSize="20sp"
android:textColor="#color/breadcrumb_text_dim"
android:textAllCaps="true"
tools:visibility="visible"/>
<TextView
android:id="#+id/crumb_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="4dp"
android:gravity="center_vertical"
android:visibility="gone"
android:fontFamily="sans-serif"
android:textAllCaps="true"
android:textSize="14sp"
android:textColor="#color/breadcrumb_text"
android:background="?selectableItemBackground"/>
</LinearLayout>
ExampleBreadcrumbs that demonstrates the basic create/updates/scroll to methods that you could easily add to your app flow. Is not 100% copy paste because your app will be a little different depending on what activity and setup your breadcrumbs would be added to. If you need anything else to get this working... let me know.
public class ExampleBreadcrumbs extends AppCompatActivity {
private static final String ROOT_NODE = "root";
private SparseArray<Long> levelNodeIds = new SparseArray<>();
private SparseArray<String> levelNodeNames = new SparseArray<>();
public int currentLevel = 0;
ViewGroup breadcrumbBar;
HorizontalScrollView breadcrumbWrapper;
String[] parents = new String[] {"Parent Item 1", "Parent Item 2",
"Parent Item 3", "Parent Item 4"};
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.examplebreadcrumbs_layout);
breadcrumbWrapper = ((HorizontalScrollView)findViewById(R.id.breadcrumb_wrapper));
breadcrumbBar = (ViewGroup) findViewById(R.id.breadcrumbs);
// TODO setup your adapter or whatever
createParentNodes();
}
#Override public void onBackPressed() {
switch (currentLevel) {
case 0:
super.onBackPressed();
break;
case 1:
createParentNodes();
adapter.notifyDataSetChanged();
break;
default:
// Get values from level you are requesting, not current.
final long id = levelNodeIds.get(currentLevel - 1);
final String name = levelNodeNames.get(currentLevel - 1);
getChildren(id, name, -1);
break;
}
}
#Override public void onItemClick(View itemView, final String name) {
long nodeId = (Long) itemView.getTag();
getChildren(nodeId, name, 1);
}
private void getChildren(final long nodeId, final String name, final int difference) {
if (nodeId != 0) {
// Example case using retrofit like setup
getChildren(nodeId, new Callback<NodesResponse>() {
#Override
public void onResponse(Call<NodesResponse> call, Response<NodesResponse> response) {
if (response.body() != null) {
if (response.body().getNodeObjs() != null && !response.body().getNodeObjs()
.isEmpty()) {
createChildNodes(nodeId, name, response.body().getNodeObjs(), difference);
}
}
}
#Override
public void onFailure(Call<NodesResponse> call, Throwable t) { // TODO}
});
} else {
createParentNodes();
adapter.notifyDataSetChanged();
}
}
private void createParentNodes() {
currentLevel = 0;
levelNodeIds.put(currentLevel, 0L);
levelNodeNames.put(currentLevel, ROOT_NODE);
listItems.clear();
int count = 0;
for(String parent : parents) {
listItems.add(new NodeObj(nodeId[count], parent, parentDescriptions[count]));
count++;
}
adapter.notifyDataSetChanged();
levelNodeNames.put(currentLevel, ROOT_NODE);
updateBreadcrumbs(true);
}
private void createChildNodes(long id, String name, List<NodeObj> NodeObjs, int difference) {
listItems.clear();
for (NodeObj obj : NodeObjs) {
listItems.add(new NodeObj(obj.getnodeId(), obj.getNodeTitle(), obj.getNodeDescription()));
}
adapter.notifyDataSetChanged();
currentLevel = currentLevel + difference;
levelNodeIds.put(currentLevel, id);
levelNodeNames.put(currentLevel, name);
// If forward, it will create new node along with updating other nodes.
updateBreadcrumbs(difference > 0);
}
private void updateBreadcrumbs(boolean createNew) {
if (createNew) {
createBreadcrumb();
}
// Loops and updates all breadcrumb nodes
updateBreadcrumbNodes();
//printDebug();
}
private void createBreadcrumb() {
boolean needToCreate = true;
// Remove view if one exists.
ViewGroup nodeToReplace = (ViewGroup) breadcrumbBar.getChildAt(currentLevel);
if (nodeToReplace != null) {
TextView toReplaceTextView = (TextView) nodeToReplace.findViewById(R.id.crumb_text);
// If node history is not the same, remove view and after.
if (toReplaceTextView.getText().equals(levelNodeNames.get(currentLevel))) {
needToCreate = false;
scrollIfBreadcrumbNotViewable(nodeToReplace);
} else {
needToCreate = true;
// Removes all nodes >= current level
for (int i = breadcrumbBar.getChildCount() - 1; i >= currentLevel; i--) {
breadcrumbBar.removeViewAt(i);
}
}
}
if (needToCreate) {
// Inflate new breadcrumb node.
final ViewGroup crumbLayout = (ViewGroup) LayoutInflater.from(this)
.inflate(R.layout.breadcrumb_text, appBarLayout, false);
crumbLayout.setTag(levelNodeIds.get(currentLevel));
// Sets name of node (color gets updated in 'updateBreadcrumbNodes').
TextView crumbTextView = (TextView) crumbLayout.findViewById(R.id.crumb_text);
crumbTextView.setVisibility(View.VISIBLE);
crumbTextView.setText(levelNodeNames.get(currentLevel));
View crumbArrow = crumbLayout.findViewById(R.id.crumb_arrow);
crumbArrow.setVisibility(levelNodeNames.get(currentLevel).equals(ROOT_NODE) ? View.GONE : View.VISIBLE);
// Add new breadcrumb node to bar.
breadcrumbBar.addView(crumbLayout, currentLevel);
scrollIfBreadcrumbNotViewable(crumbLayout);
// Create click listener to jump to history.
crumbLayout.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
int viewIndex = breadcrumbBar.indexOfChild(v);
if (viewIndex == currentLevel) return;
TextView crumbText = (TextView) v.findViewById(R.id.crumb_text);
int index = levelNodeNames.indexOfValue(crumbText.getText().toString());
long nodeId = (Long) v.getTag();
getChildren(nodeId, levelNodeNames.get(index), viewIndex - currentLevel);
}
});
}
}
private void updateBreadcrumbNodes() {
for (int i = 0; i < breadcrumbBar.getChildCount(); i++) {
boolean activeNode = i == (currentLevel);
ViewGroup node = (ViewGroup) breadcrumbBar.getChildAt(i);
TextView crumbTextView = ((TextView) node.findViewById(R.id.crumb_text));
crumbTextView.setTextColor(activeNode ? ContextCompat.getColor(this, R.color.breadcrumb_text) :
ContextCompat.getColor(this, R.color.breadcrumb_text_dim));
}
breadcrumbWrapper.fullScroll(HorizontalScrollView.FOCUS_BACKWARD);
}
private void scrollIfBreadcrumbNotViewable(final ViewGroup view) {
Rect scrollBounds = new Rect();
toolbar.getHitRect(scrollBounds);
if (!view.getLocalVisibleRect(scrollBounds) || scrollBounds.width() < view.getWidth()) {
view.postDelayed(new Runnable() {
public void run() {
breadcrumbWrapper.smoothScrollTo(view.getLeft(), 0);
}
}, 100L);
}
}
void printDebug() {
System.out.println("** DEBUG ** | level: '" + currentLevel + "' | node: id='" + levelNodeIds.get(currentLevel) + "' name='" + levelNodeNames.get(currentLevel) + "' |");
}
}
I know that this is fairly old but this seems just as good as any place to post this. There is a BreadcrumbsView via Github out there that seems to fit the need for purpose. Hope it helps anyone else looking for a similar solution.
I don't think you need a library. If you create a View (maybe a FrameLayout) and then you set it as background the same color of the Toolbar and then you put a TextView inside it, then it's done. You even can extend the TextView class and override some methods to animate the change. You can pass the current String of the breadcrumb via intents between activities and then each knows how to update it.
I know it is not possible in Android to scroll grid view horizontally. But what I am doing is adding image buttons dynamically inside horizontal scroll view like this:
public class HorizontalScroller extends Activity {
static int l=0;
private Rect mTempRect = new Rect();
static int r1=0;
static int t=0;
static int b=0;
static int x=0;
static int y=0;
//Button[] b1 = new Button[100];
ImageButton btn[][] = new ImageButton[10][10];
//ImageButton b1 = new ImageButton(this);
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout rl = (LinearLayout)findViewById(R.id.widget92);
LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
for(int i=0;i<4;i++)
{
for(int j=0;j<10;j++)
{System.out.println("helo");
/* l=l+100;
r1=r1+100;
t=t+100;
b=b+100;*/
//button();
//ImageButton btn=new ImageButton(this);
/* Rect r = mTempRect;
r.left=10;
r.top=10;
r.right=10;
r.bottom=10;
btn[i][j].getDrawingRect(r);*/
//btn[i][j].setId(j);
Rect r = mTempRect;
r.set(0,0,0,0);
Rect r2 = mTempRect;
r2.set(0,20,0,20);
btn[i][j]=new ImageButton(this);
btn[i][j]. setBackgroundResource(R.drawable.icon);
btn[i][j].setMinimumWidth(20);
btn[i][j].setMinimumHeight(20);
params1.setMargins(5, 5, 5,5);
rl.addView(btn[i][j],params1);
System.out.println("1="+btn[i][j].getTop());
System.out.println("2="+btn[i][j].getLeft());
System.out.println("3="+btn[i][j].getRight());
System.out.println("4="+btn[i][j].getBottom());
}
}
}
}
but I am getting all image buttons in a single line. How can I implement them in a grid like structure?
Implementing a horizontally scrolling GridView involves copying a few of the Android source code classes into your codebase (AdapterView, AbsListView, GridView, ScrollBarDrawable) and adding in code to handle the horizontal code. This is mainly copying some of the code and changing top to left, bottom to right, etc. The main reason for having to copy instead of extending is the final nature of those classes.
I implemented a horizontally scrolling GridView a while ago and finally got around to pushing to github:
https://github.com/jess-anders/two-way-gridview
You can
use a TableLayout inside a HorizontalScrollView, or
stay with your approach with an horizontal LinearLayout but adding vertical LinearLayouts instead of directly the images. E.g., adding three to four images per vertical LinearLayout in portrait, and redrawing to add only two in landscape.
I would try the TableLayout approach first.
PS1: for next time, try to remove all the non-relevant code (the less code is there, the easier is to understand what you did).
PS2: Remember that System.out is usually redirected to /dev/null and thus lost, so I strongly suggest you to use Log.d instead.
Complete example
Adapt this to the onCreate() method or wherever you need it:
public void horizontalScrollGalleryLayout () {
HorizontalScrollView sv = new HorizontalScrollView(this);
LinearLayout llh = new LinearLayout(this);
llh.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams layoutParamsTV = new LinearLayout.LayoutParams(40, 40);
LinearLayout.LayoutParams layoutParamsLL = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
for (int i=0; i<20; i++) {
LinearLayout llv = new LinearLayout(this);
llv.setOrientation(LinearLayout.VERTICAL);
TestView testView1 = new TestView(this, Color.rgb(i*12, 0, 0));
TestView testView2 = new TestView(this, true, Color.rgb(i*12, i*12, 0));
TestView testView3 = new TestView(this, true, Color.rgb(0, i*12, 0));
llv.addView(testView1, layoutParamsTV);
llv.addView(testView2, layoutParamsTV);
llv.addView(testView3, layoutParamsTV);
llh.addView(llv, layoutParamsLL);
}
sv.addView(llh, layoutParamsLL);
setContentView(sv);
}
I'm using a very simple View as an example:
public class TestView extends View {
Context context;
int color;
public TestView(Context context, int color) {
super(context);
this.context = context;
this.color = color;
}
#Override
public void onDraw (Canvas canvas) {
super.onDraw(canvas);
this.setBackgroundColor(Color.LTGRAY);
Paint paint = new Paint (Paint.ANTI_ALIAS_FLAG);
paint.setColor(color);
canvas.drawCircle(20, 20, 20, paint);
}
}
There is a very easy trick.
Rotate the grid view by 270 degree and set number of columns as 2.
Rotate each item to 90 degree (so that the items are displayed as original orientation).
This might be useful for some!!
I have done this way:
activity_main.xml:
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<GridView
android:id="#+id/gridView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</GridView>
</LinearLayout>
</HorizontalScrollView>
MainActivity.java:
GridView gridView = (GridView) findViewById(R.id.gridView);
gridView.setNumColumns(arrayList.size());
GridViewAdapter gridViewAdapter = new GridViewAdapter(mContext, arrayList);
gridView.setAdapter(gridViewAdapter);
// Set dynamic width of Gridview
setDynamicWidth(gridView);
Add below method:
private void setDynamicWidth(GridView gridView) {
ListAdapter gridViewAdapter = gridView.getAdapter();
if (gridViewAdapter == null) {
return;
}
int totalWidth;
int items = gridViewAdapter.getCount();
View listItem = gridViewAdapter.getView(0, null, gridView);
listItem.measure(0, 0);
totalWidth = listItem.getMeasuredWidth();
totalWidth = totalWidth*items;
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.width = totalWidth;
gridView.setLayoutParams(params);
}
Hope this will help you.
I have already posted this answer here, but both questions are
identical...
There is a nice solution in Android from now on : HorizontalGridView.
1. Gradle dependency
dependencies {
compile 'com.android.support:leanback-v17:23.1.0'
}
2. Add it in your layout
your_activity.xml
<!-- your stuff before... -->
<android.support.v17.leanback.widget.HorizontalGridView
android:layout_width="wrap_content"
android:layout_height="80dp"
android:id="#+id/gridView"
/>
<!-- your stuff after... -->
3. Layout grid element
Create a layout for your grid element ( grid_element.xml ). I have created a simple one with only one button in it.
<?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="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button"
android:id="#+id/button" />
</LinearLayout>
4. Create an adapter
Highly inspired by this link : https://gist.github.com/gabrielemariotti/4c189fb1124df4556058
public class GridElementAdapter extends RecyclerView.Adapter<GridElementAdapter.SimpleViewHolder>{
private Context context;
private List<String> elements;
public GridElementAdapter(Context context){
this.context = context;
this.elements = new ArrayList<String>();
// Fill dummy list
for(int i = 0; i < 40 ; i++){
this.elements.add(i, "Position : " + i);
}
}
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
public final Button button;
public SimpleViewHolder(View view) {
super(view);
button = (Button) view.findViewById(R.id.button);
}
}
#Override
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(this.context).inflate(R.layout.grid_element, parent, false);
return new SimpleViewHolder(view);
}
#Override
public void onBindViewHolder(SimpleViewHolder holder, final int position) {
holder.button.setText(elements.get(position));
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "Position =" + position, Toast.LENGTH_SHORT).show();
}
});
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemCount() {
return this.elements.size();
}
}
5. Initialize it in your activity :
private HorizontalGridView horizontalGridView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_activity);
horizontalGridView = (HorizontalGridView) findViewById(R.id.gridView);
GridElementAdapter adapter = new GridElementAdapter(this);
horizontalGridView.setAdapter(adapter);
}
Use recyclerview with setting its gridlayout as layout manager and set it to horizontal scroll
your recycle view.setLayoutManager(new GridLayoutManager(getActivity(),2, LinearLayoutManager.HORIZONTAL, false))
here 2 is the column span for grid
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();
}