I am using an AlertDialog to track a logFile which is updating in real time, and need to automatically scroll to the bottom of the view whenever an extra line is added.
I am able to cast the AlertDialog to a TextView (and e.g. using this TextView alter the text size) but any methods involving scrolling don't work.
Code:
LogFileView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
String logFile = "/data/data/com.test/test.log";
String logFileOutput = getFileOutput(logFile);
final AlertDialog dialog = new AlertDialog.Builder(getActivity()).setMessage(logFileOutput).show();
TextView textView = dialog.findViewById(android.R.id.message);
textView.setTextSize(8);
textView.scrollTo(0, textView.getLineCount());
} catch (IOException e) {
e.printStackTrace();
}
}
});
textView.setTextSize(8); will alter the text size on display
textView.scrollTo(0, textView.getLineCount()); will do nothing, and the alert dialog, despite having a scrollbar available, will remain focussed on the first line
Update 1:
I see there are a few requests for the dialog creation code/errors in the console output.
Firstly, I am not actually using a separate layout/class to create the dialog. It is applying the default layout associated with (android.R.id.message) to an instance of android.app.AlertDialog and is only constructed within the onClick method for the onClickListener in the code above.
Based on the feedback I've received so far, the code I've most recently attempted to use looks as follows:
LogFileView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
String logFile = "/data/data/com.test/test.log";
String logFileOutput = getFileOutput(logFile);
final AlertDialog dialog = new AlertDialog.Builder(getActivity()).setMessage(logFileOutput).show();
TextView textView = dialog.findViewById(android.R.id.message);
textView.setTextSize(8);
//textView.scrollTo(0, textView.getLineCount());
textView.setMovementMethod(new ScrollingMovementMethod());
textView.post(new Runnable() {
#Override
public void run() {
textView.scrollTo(0, textView.getLineCount());
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
});
Secondly, there is nothing appearing in the console when the scroll attempt is made - this simply gets ignored at runtime.
The default layout seemed like it would be fine for my purpose, given it appears like a blank TextView with a scrollbar attached, but I think it may be a sensible next step to use a new custom layout and add a ScrollView and see what happens
Use below code. I Tested & verified.
textView.movementMethod = ScrollingMovementMethod() // Add this
textView.text = "your text"
textView.post {
val scrollAmount = textView.layout.getLineTop(textView.lineCount) - textView.height
textView.scrollTo(0, textView.lineCount)
}
Edit:
Equivalent to java:
textView.setMovementMethod(new ScrollingMovementMethod());
textView.setText("your text");
textView.post(new Runnable() {
#Override
public void run() {
int scrollAmount = textView.getLayout().getLineTop(textView.getLineCount()) - textView.getHeight();
textView.scrollTo(0, scrollAmount);
}
});
Try to wrap it with post instead of calling directly to scrollTo,
something like this:
textView.post(new Runnable() {
#Override
public void run() {
textView.scrollTo(0, textView.getLineCount());
}
});
Related
I have a edit text and i want to push it up when user click on it. that is it should be completely visible to user.
Now the problem is when i write some line and my keyboard is visible , then if i again click on edittext then only first line is visible .
here is my onClickListner of edittext....
content.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final Runnable r = new Runnable() {
public void run() {
scrollView.scrollTo(0, send.getTop()); //send is a button place below edittext.
}
};
scrollView.postDelayed(r, 200);
}
});
Put this in your manifest, in the activity where you want this to happen.
<activity android:windowSoftInputMode="adjustPan">
RecylerView contains a textView "Some content" in the last.I am not able to scroll my recylerview to last text to be shown.I have tried every hit and trial method found to me,but not able to find any solution.
Code which i have tried:-
1. onView(withId(R.id.recylerview)).perform(scrollToPosition(13));
//my last text view in recyler view is at position 13
2.onView(withText("Some content")).perform(scrollTo(), click());
//my text is "Some content"
My problem is that i cannot search it with id as recycler view contains same text view for all 13 items.As i have set text value programmatically.
So this code cannot apply:-
onView(withId(R.id.txtview)).perform(scrollTo(), click());
EspressoCode
UiObject2 button9 = device.findObject(By.text("S 5 [None]"));
button9.click();
try {
UiObject srText = new UiObject(new UiSelector().resourceId("com.example.project:id/radio"));
sText.click();
}catch(Exception e){
}
onView(withRecyclerView(R.id.recylerview).atPosition(13))
.check(matches((hasDescendant(withText("Some content")))));
UiObject2 button10 = device.findObject(By.text("S 6 [None]"));
button10.click();
try {
UiObject sensorText = new UiObject(new UiSelector().resourceId("com.example.project:id/radio"));
sensorText.click();
}catch(Exception e){
}
You could add this RecyclerViewMatcher file to your tests. Then add this method to your espresso test so you can use it
public static RecyclerViewMatcher withRecyclerView(final int recyclerViewId) {
return new RecyclerViewMatcher(recyclerViewId);
}
and finally do
onView(withRecyclerView(R.id.recyclerview).atPosition(13))
.check(matches((hasDescendant(withText("Some content")))));
So your espresso file would look something like..
public class YouEspressoTest {
public static RecyclerViewMatcher withRecyclerView(final int recyclerViewId) {
return new RecyclerViewMatcher(recyclerViewId);
}
#Before
public void setUp() {
...
}
#Test
public void testRecyclerView() {
...
onView(withRecyclerView(R.id.recyclerview).atPosition(13))
.check(matches((hasDescendant(withText("Some content")))));
...
}
}
This code was working until last night, but now now. I'm wanting a value to be record that is linked to the buttons, I have used set and get tag but is only returning last value.
//create a layout
LinearLayout layout = (LinearLayout)findViewById(R.id.linearlayout);
// create a list of buttons
for(x=0; x<3; x++)
{
newBut = new Button(this);
newBut.setText("("TEXT");
newBut.setTextColor(Color.parseColor("#FFFFFF"));
newBut.setTag(x); //hide job id within the button.
newBut.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
int newValue = Integer.parseInt(newBut.getTag().toString());
System.out.println(newValue); //this just a test to display the value
}
});
layout.addView(newBut);
}
Is the error obvious - not to me.
It is returning the last value, because in all the created listeners you always reference the same button (last value of newBut variable), ignoring the actual click source view you have as the argument. Is should be:
newBut.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
int newValue = Integer.parseInt(v.getTag().toString());
System.out.println(newValue);
}
});
I create an application in android studio and I need advice, I got one button, and I need to change the text on the second button clicks through to the first. I have a code that changes only TextView but not the text on the button.
NewText = (TextView)findViewById(R.id.textView1);
ChangeText = (Button)findViewById(R.id.ch_txt_ger);
final TextView finalNewText1 = NewText;
ChangeText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Set Text on button click via this function.
finalNewText1.setText(" (Frohe Weihnachten) ");
}
});
Same concept as you did for textView
Button SecondButton,ChangeText; // declaring the buttons
SecondButton = (Button)findViewById(R.id.button2);
ChangeText = (Button)findViewById(R.id.ch_txt_ger);
ChangeText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//This changes the text on the second button
SecondButton.setText("New Text Here");
}
});
SecondButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Do anything
}
});
Button ChangeText;
ChangeText = (Button)findViewById(R.id.ch_txt_ger);
ChangeText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//part to change the button text
Button tmp_button = (Button)findViewById(R.id.ch_txt_ger);
tmp_button.setText("Frohe Weihnachten");
//part to change the textview text
TextView NewText
NewText = (TextView)findViewById(R.id.textView1);
finalNewText1.setText(" (Frohe Weihnachten) ");
}
});
After Clicking outlooking
Here you go: You can define a temporary button variable and make the change on it if setting the same button on its own clicking is causing problems.
And if the text will not change according to user, and if you know it like On/OFF, Red/Green you can also code it with a selector file which would make the java code look more clean.
A tiny advise: Defining the TextViews and Buttons that will get affected should all be written in the same function and close to the place where they are being changed for you to keep track of where you coded them.
I would add one thing, in case if you want to save the new button name when you close and reopen your app, you could use Shared Preferences: https://developer.android.com/training/basics/data-storage/shared-preferences.html
I've coded a custom dialog for my application but once I try to open it, I got a lag and the following message is displayed in the logcat console:
Skipped 31 frames! The application may be doing too much work on its main thread.
To lower the work, I've moved the Typeface loading to an AsyncTask but it doesn't solve my problem.
public class CustomDialog
{
private Context context = null;
private Dialog dialog = null;
private boolean cancelable = true;
private OnCancelListener cancelListener = null;
private Typeface latoFont = null;
private RelativeLayout layout_root = null;
private TextView text_title = null;
private TextView text_message = null;
private LinearLayout layout_buttons = null;
public CustomDialog(Context context)
{
this.context = context;
this.dialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);
this.dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.dialog.setContentView(R.layout.dialog);
this.dialog.setCancelable(true);
layout_root = (RelativeLayout) dialog.findViewById(R.id.layout_root);
text_title = (TextView) dialog.findViewById(R.id.text_title);
text_message = (TextView) dialog.findViewById(R.id.text_message);
layout_buttons = (LinearLayout) dialog.findViewById(R.id.layout_buttons);
// Set background color
layout_root.setBackgroundColor(FlatUtils.transparentDark(FlatConstants.DOMIANT_COLOR));
// Set font
new TypeFaceTask(context, new TextView[]{text_title, text_message}).execute();
// Attach listener
layout_root.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view)
{
if (view.getId() != R.id.layout_root) return;
if (cancelable)
{
if (cancelListener != null) cancelListener.onCancel();
dialog.dismiss();
}
}
});
}
public void setTitle(String title)
{
text_title.setVisibility(View.VISIBLE);
text_title.setText(title);
}
public void setMessage(String message)
{
text_message.setVisibility(View.VISIBLE);
text_message.setText(message);
text_message.setMovementMethod(new ScrollingMovementMethod());
}
public void addButton(String value, final OnClickListener listener)
{
// Create button
FlatButton button = new FlatButton(context);
button.setText(value);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, dpToPx(40));
params.setMargins(0, dpToPx(10), 0, 0);
layout_buttons.addView(button, params);
// Set typeface
if (latoFont != null) button.setTypeface(latoFont);
// Attach listener
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view)
{
if (listener != null) listener.onClick(view);
dialog.dismiss();
}
});
}
public void setCancelable(boolean b)
{
cancelable = b;
dialog.setCancelable(b);
}
public void setOnCancelListener(OnCancelListener listener)
{
this.cancelListener = listener;
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog)
{
cancelListener.onCancel();
}
});
}
public void show()
{
dialog.show();
}
public void dismiss()
{
dialog.dismiss();
}
public interface OnCancelListener {
public void onCancel();
}
private int dpToPx(int dp)
{
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return (int)(dp * (metrics.densityDpi / 160f));
}
}
This is way I create a new dialog:
CustomDialog dialog = new CustomDialog(TestActivity.this);
dialog.addButton("Hello 1", null);
dialog.addButton("Hello 2", null);
dialog.addButton("Hello 3", null);
dialog.setTitle("Dummy dialog");
dialog.setMessage("Plop plop");
dialog.show();
So my question is: Is there a way to optimized this code ?
First of all i think you should try extending the Dialog class instead of wrapping it like this...Your code will be cleaner and more reusable and i think will yield some performance improvement. It wont take you much, most of the code will be the same, but its a general rule of thumb if you want a custom Dialog you should extend the existing elements, similar to when you create an Activity or Fragment you extend them :).
Also i dont know what you are actually doing with your layouts but i see you are getting the screen width and height and then setting margins etc...Such calculations can cause your frames to skip and i would advise you to try making the layout through xml. Trust me, just try playing with layout params through xml and i bet you will get the same result when it comes to margins padings and the overal look, and use the different layout folders(and dimens for margins and paddings for ex) for different screen densities and sizes to achieve the same look across all devices. Not to mention this will perform faster.
Edit 1:
Typefaces wont cause such problems.
I see you said you are running this on emulator?! Well thats the issue :) i can guarantee that wont happen on a real device. :)) its a common thing on the emulator. Always develop on real devices, only they can mimic all the real problems and bugs you will encounter.
But still listen to the advice's here and follow "best practices" when programming.
is it phone or emulator? (try to run on phone)
Best practice - to extend DialogFragment(Dialog)
Adding buttons from code is strange :) You can declare yor dialog ui using XML layout, inflate it and set inflated view as content in your dialog
You don't need to load Typeface in asynctask.
So my general suggestion is to learn best practices of creating dialogs.