I'm creating a chat application, on launch it displays the twenty most recent messages in a conversation. When you scroll to the top you can press a button to display earlier messages. Pretty typical. The only problem is, I want the UI elements to maintain their position after pressing the button. At the moment they shift. I've created a stripped out version of the problem I'm having.
Before pressing the button
After pressing the button
As you might have guessed, I would like it so that after I press the button the TextView with the label 51 (TextView-51) appears as if it hasn't moved. My original plan was to get the position of TextVie-51 before the button press, and then after the button press, and set the ScrollView's Y position. However that approach doesn't work because the at the time I was checking the View hadn't inflated yet.
Here's the layout xml
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/TestScroller">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:id="#+id/mainContainer" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/TestButton"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:onClick="insertMore"
android:text="Get Earlier Messages" />
</RelativeLayout>
</ScrollView>
Here's the code for the activity.
protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.test);
lastId = R.id.TestButton;
firstId = -1;
RelativeLayout rl = (RelativeLayout)findViewById(R.id.mainContainer);
//1. Create fifty TextViews and put them under the button.
for (int i = 51; i <= 100; i++)
{
TextView tv = new TextView(this);
tv.setText(Integer.toString(i));
tv.setId(i + 100);
final int WC = RelativeLayout.LayoutParams.WRAP_CONTENT;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(WC, WC);
params.addRule(RelativeLayout.BELOW, lastId);
tv.setLayoutParams(params);
lastId = tv.getId();
if (firstId == -1)
firstId = tv.getId();
rl.addView(tv);
}
}
public void insertMore(View view)
{
//Create fifty more TextViews and insert them between the button and
//the already created textviews.
RelativeLayout rl = (RelativeLayout)findViewById(R.id.mainContainer);
lastId = R.id.TestButton;
for (int i = 0; i <= 50; i++)
{
TextView tv = new TextView(this);
tv.setText(Integer.toString(i));
tv.setId(i + 100);
final int WC = RelativeLayout.LayoutParams.WRAP_CONTENT;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(WC, WC);
params.addRule(RelativeLayout.BELOW, lastId);
tv.setLayoutParams(params);
lastId = tv.getId();
rl.addView(tv);
}
//Now make sure the textview with the label 51 under it is underneath the last
//view we just added.
TextView tv = (TextView)findViewById(firstId);
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)tv.getLayoutParams();
params.addRule(RelativeLayout.BELOW, lastId);
tv.setLayoutParams(params);
//Remove the button
Button button = (Button)findViewById(R.id.TestButton);
rl.removeView(button);
}
Based on your first idea which was to scroll to the bottom of the list after adding textviews, did you try to call requestLayout() to force layout update :
public void insertMore(View view)
{
// Create and add your 50 views
...
// force Update layout
rl.requestLayout();
scrollView.post(new Runnable() {
#Override
public void run() {
// Scroll to scrollviews bottom
scrollView.scrollTo(0, scrollView.getBottom());
}
});
}
Related
In one of the activity of my app, I have a button where I want to display an image with each button click. For example:
By clicking the button of my activity, an image appears on screen as shown.
The second and following clicks on the button will results in the new image to append accordingly.
I would like to have some suggestion on how do I achieve this.
I made something similar to this but with TextView. Basically I did this:
XML:
For my case I made TableLayout Ex:
<TableLayout
android:id="#+id/existedTableLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin_standard">
<TableRow>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/number_text"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Large" />
</TableRow>
</TableLayout>
Activity
Note: Change it to ImageView for your case
/* //Get the TableLayout. Ex:
private TableLayout existedTableLayout = findViewById(R.id.existedTableLayout);
*/
/* Make onClickListerner to call below function */
private void addTableRowDynamically() {
//Make new Row
TableRow newRow= new TableRow(this);
TextView newNoTextView = new TextView(this);
//some TextView method, do your research about ImageView
newNoTextView.setLayoutParams(new TableRow.LayoutParams(0,ViewGroup.LayoutParams.WRAP_CONTENT, 1));
newNoTextView.setText("this is text");
newNoTextView.setTextAppearance(this, android.R.style.TextAppearance_DeviceDefault_Large);
// Add the TextView to the newRow
newRow.addView(newNoTextView);
// Add the newRow which contain the TextView to the TableLayout, below
existedTableLayout.addView(newRow, existedTableLayout.getChildCount());
}
Add a vertical LineaLayout and add views dynamically:
private void createViews() {
for (int i = 0; i < numberOfViews; i++) {
view = new ImageView(context);
int width = 300;
int height = 50;
view.setPadding(18, 10, 0, 0);
view.setLayoutParams(new LinearLayout.LayoutParams(width, height));
view.setId(i);
view.setGravity(Gravity.CENTER_VERTICAL);
view.setBackgroundColor(Color.parseColor("someColor"));
viewList.add(view);
}
}
Rect rectf = new Rect();
for (ImageView view : viewList) {
view.getGlobalVisibleRect(rectf);
coordinates.add(rectf.bottom);
}
I'm trying to add some buttons dynamically in horizontal order. I have tried several options and none of them worked.
What am i doing wrong?
RelativeLayout layout = (RelativeLayout) findViewById(R.id.pickItem);
RelativeLayout.LayoutParams buttonParams =
new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
buttonParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
buttonParams.addRule(RelativeLayout.CENTER_VERTICAL);
String userName;
List<CheckBox> usersButtonList=new ArrayList<CheckBox>();
int i=0;
for(User user : users){
userName=user.getName();
CheckBox Userbutton = new CheckBox(this);
usersButtonList.add(Userbutton);
Userbutton.setText(userName);
Userbutton.setId(i);
Userbutton .setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean isChecked=((CheckBox)v).isChecked();
String s= (String)((CheckBox)v).getText();
updateActiveUsers(isChecked,s);
}
});
if(i!=0)
{
buttonParams.addRule(RelativeLayout.ALIGN_RIGHT,(i-1));
}
layout.addView(Userbutton,buttonParams);
i++;
}
There are a few things wrong with this. First, like #EasyJoin Dev said, substitute RelativeLayout with LinearLayout in your layout xml and set the orientation to horizontal. It should look something like this
<LinearLayout
android:id="#+id/pickItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
</LinearLayout>
Then change the two top lines in your code to
LinearLayout layout = (LinearLayout) findViewById(R.id.pickItem);
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Since you have ViewGroup.LayoutParams.FILL_PARENT it will take the whole space available. Let me know if you need any more help or this doesn't work
I have been attempting to programmatically add buttons based on a list of values.
PROBLEM: Only one button is produced, rather than a series. This button contains the information of the last value in the array.
I gather an array of values aptly named 'values', I then use a for loop to add the buttons.
Here is the code of my loop to add buttons:
public void updateButtons(List<String> values, View rootView) {
//Find relative layout
RelativeLayout rl = (RelativeLayout) rootView.findViewById(R.id.RelativeLayoutManage);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(50, 10, 50, 10);
for (String mTrip : values) {
//New button
Button Postbtn = new Button(mContext);
//Style
Postbtn.setBackgroundResource(R.drawable.buttonshape);
Postbtn.setTextColor(getResources().getColor(R.color.DarkGreen));
Postbtn.setTextSize(25);
//set text
Postbtn.setText(mTrip.toString());
//set id
Postbtn.setId(i);
int id_ = Postbtn.getId();
//Add to view
rl.addView(Postbtn, params);
Postbtn = ((Button) rootView.findViewById(id_));
//Add listener
Postbtn.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
Log.v("TripNumber", Integer.toString(i));
//TODO: Change Fragment
}
});
i++;
}
}
And my corresponding layout file if needed:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="#+id/RelativeLayoutManage"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
</RelativeLayout>
Seems that they might be overlapping each other. You need to use a LinearLayout
<LinearLayout android:id="#+id/RelativeLayoutManage"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
/>
You are adding Button to RelativeLayout. In your current code all your buttons are present but one above other. You should make one below/above other to make all buttons visible. Else use a LinearLayout
I solved the problem by positioning each button as it is added to the layout. Simply using:
params.addRule(RelativeLayout.BELOW, Postbtn.getId() - 1);
Postbtn.setLayoutParams(params);
I want to create a function that takes in an array of text and creates buttons and adds them to the view.
This is my code.
It is working and creating the buttons but when i call the function twice it doesn't create two linear layouts it just shows the last one called as if it is deleting the first one.
How can i make it to create a new linear layout and add it to the View?
// Create a view
protected boolean CreateTheButtons(String[] names)
{
try
{
LinearLayout linLayout = new LinearLayout(this);
linLayout.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams linLayoutParam = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// set LinearLayout as a root element of the screen
linLayout.setWeightSum(names.length);
setContentView(linLayout, linLayoutParam);
LayoutParams lpView = new LayoutParams(0, LayoutParams.WRAP_CONTENT);
lpView.weight = 1;
for (int i = 0; i < names.length; i++) {
Button btn = new Button(this);
btn.setText(names[i]);
linLayout.addView(btn, lpView);
}
return true;
}
catch(Exception ex)
{
return false;
}
}
It is working and creating the buttons but when i call the function
twice it doesn't create two linear layouts it just shows the last one
called as if it is deleting the first one.
Your code removes the first LinearLayout resulted from calling the method because you use setContentView()(which will replace the current view of the activity(if any is found) with the view that you pass as a parameter). Instead you should remove the call to setContentView() and insert a holder ViewGroup for the LinearLayouts that you plan to add through that method.
<!-- This will be the content view of the activity -->
<?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/parent" />
Set the layout above as the content view for the activity, in the onCreate() method:
setContentView(R.layout.the_layout_above);
In the method you'll then have:
protected boolean CreateTheButtons(String[] names) {
try {
LinearLayout linLayout = new LinearLayout(this);
linLayout.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams linLayoutParam = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
linLayout.setWeightSum(names.length);
// assuming this method is in an Activity
LinearLayout parent = (LinearLayout) findViewById(R.id.parent);
parent.addView(linLayout, linLayoutParam);
LayoutParams lpView = new LayoutParams(0, LayoutParams.WRAP_CONTENT);
lpView.weight = 1;
for (int i = 0; i < names.length; i++) {
Button btn = new Button(this);
btn.setText(names[i]);
linLayout.addView(btn, lpView);
}
return true;
} catch(Exception ex) {
return false;
}
}
i have this sample and i am trying to Implement a Click on item(s) inside sub view
i have this two xml files
this is the subview.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/textLabel"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:textSize="50dip"
android:textColor="#00FF00"
android:textStyle="bold"/>
</LinearLayout>
this is the scrollview.xml view:
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="none">
<LinearLayout
android:layout_width="fill_parent"
android:id="#+id/scrollviewlinearlayout"
android:layout_height="fill_parent">
</LinearLayout>
</HorizontalScrollView>
and this is the Activity:
public class TestTwo extends Activity {
Context mContext;
HorizontalScrollView mScrollView;
LinearLayout mLinearLayout;
LinearLayout.LayoutParams mLinearLayoutParams;
Display mDisplay;
// scroll behaviour
private int mScrollStartPosition;
private static final float SCROLL_MARGIN = 0.2f;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
// load layout from xml and get references to sub-views
setContentView(R.layout.scrollview);
mScrollView = (HorizontalScrollView) findViewById(R.id.scrollview);
mLinearLayout = (LinearLayout) findViewById(R.id.scrollviewlinearlayout);
// get a display reference (used to find screen size)
mDisplay = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
// get the layout parameters to apply to the sub-views
mLinearLayoutParams = new LayoutParams(mDisplay.getWidth(), mDisplay.getHeight());
// add some views to the ScrollView
addViewsToScrollView();
}
private void addViewsToScrollView() {
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
for (int i = 0; i < 3; i++) {
// inflate view from xml
View child = inflater.inflate(R.layout.subview, null);
// give it a number
final TextView text = (TextView) child.findViewById(R.id.textLabel);
text.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
text.setText("Test");
}
});
text.setText("" + (i + 1));
// give it a colour
text.setBackgroundColor(Color.rgb((int) (Math.random() * 255), (int) (Math.random() * 255),
(int) (Math.random() * 255)));
// apply layout parameters, and add it
child.setLayoutParams(mLinearLayoutParams);
mLinearLayout.addView(child);
}
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int viewWidth = mDisplay.getWidth(); // width of each view
int triggerWidth = (int) (SCROLL_MARGIN * viewWidth); // amount user has to scroll to move to next view
int pos = mScrollView.getScrollX();
int diff = pos % viewWidth; // offset of current scroll from leftmost view's snap position
int posLeftView = pos - diff; // absolute snap position of the leftmost view on screen
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// Record the starting scroll position. This is used to decide the scroll direction.
mScrollStartPosition = pos;
break;
case MotionEvent.ACTION_UP:
if (pos > mScrollStartPosition) {
// Scrolling right
if (diff > triggerWidth) mScrollView.smoothScrollTo(posLeftView + viewWidth, 0);
else mScrollView.smoothScrollTo(posLeftView, 0);
} else {
// Scrolling left
if (diff > (viewWidth - triggerWidth)) mScrollView.smoothScrollTo(posLeftView + viewWidth, 0);
else mScrollView.smoothScrollTo(posLeftView, 0);
}
// replacing our scrollTo command with it's own
return true;
}
return super.dispatchTouchEvent(ev);
}
}
i tried to debug it and it seems its not fire the onClick event
can you help me please with this problem ?
You're doing a bunch of wild things that I'll leave for another time. Try text.setClickable(true) on your final TextView text
Ok sorry for all these edits. here are your problems though.
you shouldn't use the child statement
2. you shouldn't be setting an onclick listener for an item thats not within the current content
So......
final TextView text = (TextView) child.findViewById(R.id.textLabel);
should be
final TextView text = (TextView) findViewById(R.id.textLabel);
since the content needs to be set to the proper xml file
setContentView(R.layout.scrollview);
would need to be
setContentView(R.layout.<NAME OF SECOND XML FILE WHICH U DIDNT INCLUDE>);