I have an Android app, inside I have 3 TextViews in a vertical LinearLayout. I want to blur parts of the TextViews by a String array containing the words that should be blurred. The TextViews looks like this.
In this example, I want to blur all the occurrences of the words "than" and "third".
I currently blur the text using a BlurMaskFilter like in this answer. However, it blurs the whole text in the TextView, and I want to blur specific words only.
My solution was replacing the 3 TextViews by 3 horizontal LinearLayouts and loop through the text of the TextViews, when reaching a word that needs to be blurred, split the TextView to three TextViews: start, blurred part, end. In our example, it will be "this is the", "third"(blurred), "textview" for the third TextView.
The problem I get can be seen here:
So as you can see, when the text reaches more than one row, the second line won't start from the start of the screen, as it is a LinearLayout and the view before it takes some space. What I want to achieve is being able to cut a TextView in the middle of a line, even if it is a multiline TextView, add another TextView right next to it and blur it, and add the continuation of the text afterward, and it'll start the next line from the beginning. I don't know any layout type that will fit these needs, nor a way of achieving it in a different way.
My current code to achieve the state shown in the last picture:
Activity --> create the texts, and append them to the layouts:
LinearLayout linear0 = findViewById(R.id.testlinear0);
LinearLayout linear1 = findViewById(R.id.testlinear1);
LinearLayout linear2 = findViewById(R.id.testlinear2);
TextView firstTextView = new TextView(this);
firstTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
setHtmlText(firstTextView, "adsada");
firstTextView.setTextAppearance(this, R.style.WikiTextViewStyle);
TextView aaa = new TextView(this);
aaa.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
setHtmlText(aaa, HelperClass.levelsContent.get(levelName)[0]);
aaa.setTextAppearance(this, R.style.WikiTextViewStyle);
TextView secondTextView = new TextView(this);
secondTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
setHtmlText(secondTextView, HelperClass.levelsContent.get(levelName)[1]);
secondTextView.setTextAppearance(this, R.style.WikiTextViewStyle);
TextView thirdTextView = new TextView(this);
thirdTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
setHtmlText(thirdTextView, HelperClass.levelsContent.get(levelName)[2]);
thirdTextView.setTextAppearance(this, R.style.WikiTextViewStyle);
thirdTextView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
float radius = thirdTextView.getTextSize() / 3;
BlurMaskFilter filter = new BlurMaskFilter(radius, BlurMaskFilter.Blur.NORMAL);
thirdTextView.getPaint().setMaskFilter(filter);
linear0.addView(firstTextView);
linear0.addView(aaa);
linear1.addView(secondTextView);
linear2.addView(thirdTextView);
layout -->
<LinearLayout
android:id="#+id/imgLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="#+id/testlinear0"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="#+id/testlinear1"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="#+id/testlinear2"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
perhaps use a SpannableString and mark the portion of text you want to be blurred using a MaskFilterSpan? For example:
SpannableString string = new SpannableString("Text with blur mask");
MaskFilter blurMask = new BlurMaskFilter(5f, BlurMaskFilter.Blur.NORMAL);
string.setSpan(new MaskFilterSpan(blurMask), 10, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(string);
Related
I need to add TextViews to a Layout (RelativeLayout or LinearLayout I don't care) programatically.
I want something like this:
After the textview 4 there is no more space on the right side so the next TextView will be placed in a new Line bellow.
This is what I have done:
Create a LinearLayout in the xml file:
<LinearLayout
android:id="#+id/my_linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
In my code, I loop over a list of Objects and add a new TextView for each objekt:
LinearLayout myLinearLayout = (LinearLayout) itemView.findViewById(R.id.my_linear_layout);
for(MyObject object : myObjectList) {
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(20, 0, 20, 0); // llp.setMargins(left, top, right, bottom);
final TextView textView = new TextView(context);
textView.setText(object.getName());
textView.setLayoutParams(params);
myLinearLayout.addView(textView, params);
}
But this is the result I get:
I have thought adding LinearLayouts vertically instead of TextViews, but still my problem is that I don't know when I need to add the next the next one, I mean, when there is no more space on the right side.
I have also tried it with TableLayout but still the same problem, I don't know when I have to add the next row.
Any ideas? Maybe there is a View that already solves that problem and I don't know...
What I Tried To Do
I tried to set my ImageButton's layout_gravity via Java code, the way I want the ImageButton to be is presented like the way within the Orange frame in the image below:
The Blue frame is a vertical LinearLayout act as a "base" layout and this is the layout I tried to add child layouts to.
The Orange and Red are both horizontal LinearLayout.
The Orange layout is the way I want to put the ImageButton and the TextView, this one is set up via XML
The Red layout is the result I tried to mimic the Orange layout via Java code.
The Related Code
Here's the XML code that set up the Orange layout, this is the effect I want to achieve via Java code:
<!-- Begin the Orange Layout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/info_left_padding"
android:layout_marginRight="#dimen/info_right_padding" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:minHeight="#dimen/detail_min_line_item_height"
android:text="TextView" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageButton
android:id="#+id/imageButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|center_vertical"
android:adjustViewBounds="true"
android:maxHeight="#dimen/abs__action_bar_default_height"
android:scaleType="fitCenter"
android:src="#drawable/navigation_cancel" />
</FrameLayout>
</LinearLayout>
Here's the Java code that set up the Red layout
int textHeight = (int)getResources().getDimension(R.dimen.detail_min_line_item_height);
int imgHeight = (int)getResources().getDimension(R.dimen.abs__action_bar_default_height);
TextView mTextView = new TextView(this);
ImageButton mDeleteButton = new ImageButton(this);
// Set Delete Button Padding
// mDeleteButton.setPadding(buttonPadding, buttonPadding, buttonPadding, buttonPadding);
// Set Imagebutton Scale type as fitCentre
mDeleteButton.setScaleType(ScaleType.FIT_CENTER);
// Set AdjustViewBounds
mDeleteButton.setAdjustViewBounds(true);
// Set max height of the image
mDeleteButton.setMaxHeight(imgHeight);
// Set the text appearance to be "large"
mTextView.setTextAppearance(this, android.R.style.TextAppearance_Large);
mTextView.setText(text);
// Set the minimum height of this textview
mTextView.setMinHeight(textHeight);
// Set the content of the textview to be centred
mTextView.setGravity(Gravity.CENTER_VERTICAL);
// Set the ImageButton's background image
mDeleteButton.setImageResource(R.drawable.navigation_cancel);
LinearLayout.LayoutParams hParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
LinearLayout hLayout = new LinearLayout(this);
// Set Margins
hParams.leftMargin = (int) getResources().getDimension(R.dimen.info_left_padding);
hParams.rightMargin = (int) getResources().getDimension(R.dimen.info_right_padding);
hParams.bottomMargin = (int) getResources().getDimension(R.dimen.text_layout_margin);
hLayout.setLayoutParams(hParams);
// Set orientation to horizontal
hLayout.setOrientation(LinearLayout.HORIZONTAL);
// The settings below is actually setting up some of the button's parameters
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
buttonParams.gravity = Gravity.RIGHT;
mDeleteButton.setLayoutParams(buttonParams);
hLayout.addView(mTextView);
hLayout.addView(mDeleteButton);
layout_blue.addView(hLayout);
What I've Tried So Far
According to some SO post like this: Java method for android:layout_gravity I initially tried to first put my ImageButton into a FrameLayout then set the params of this FrameLayout, like this:
FrameLayout buttonFrame = new FrameLayout(this);
FrameLayout.LayoutParams buttonParams = new FrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
android.widget.FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.RIGHT | Gravity.CENTER_VERTICAL);
buttonFrame.setLayoutParams(buttonParams);
buttonFrame.addView(mDeleteButton);
But I had the same result as the image presented above. Later I also tried to change the LayoutParams width to MATCH_PARENTonly to find theImageButton` was stretched horizontally (Yes it's stretched)
Then I tried the method posted in these two SO posts:
How to set layout_gravity programmatically?
How to set a button's parameters programatically
Their method is to set up a LinearLayout.Params first, then apply this params to the button (The Code I posted in The Related Code section applies this method). In short it is:
// The settings below is actually setting up some of the button's parameters
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
buttonParams.gravity = Gravity.RIGHT;
mDeleteButton.setLayoutParams(buttonParams);
However, the result was still the same as the image presented above.
Question
Since I need to programmatically add more child views to the Blue layout later, I wonder if there's a way to set up each child layout like the Orange one in the image?
At Last
I found a solution which is quite similar to #Permita 's answer.
Here's my solution:
LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams(0, LayoutParams.WRAP_CONTENT);
textParams.weight = 1.0f;
mTextView.setLayoutParams(textParams);
Add the below code, it will assign all the available space to the texView, shifting the button to right side of the layout to make it appear like the orangeLayout.
mTextView.setLayoutParams(LayoutParams param = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT, 1.0f));
Try layout_width = "0dp" layout_weight="1" for the TextView. This tells TextView to occupy the whole available width, so that FrameLayout with ImageView will align to the right border.
<TextView
android:id="#+id/textView1"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:minHeight="#dimen/detail_min_line_item_height"
android:text="TextView" />
Instead of using the standard LinearLayout, why not try to use the more complex RelativeLayout? With it, you can adjust the locations of each individual view relative to others. You can set the ImageButton in the orange layout to android:layout_alignParentRight="true", which will set the button attached to the right side of the parent layout, the RelativeLayout in my case, but the LinearLayout in yours. Here is the link to the API Guides for Relative Layouts on the Android developers website.
I am using linear layout with 2 textviews, 4 buttons, 1 seekbar,1 image view. If I am place those textviews,buttons, etc. in a linear layout the alignment is fine in android phone. While I am running the same code in android tablet, alignment is not proper. Why this alignment is not proper in tablet.? I have created the textviews,buttons etc by java code. Even I am specifying the two text views horizontally by settings the left margin of the second text view by devicewidth/2 having the difference in android phone and tablet. I need to align like the below.
TextView1 TextView2
Button1 Button2 Button3 Button4 SeekBar ImageView
Here is my code.
LinearLayout.LayoutParams textViewParams1 = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
textViewLayout.setOrientation(LinearLayout.HORIZONTAL);
TextView TextView1=new TextView(this);
TextView1.setText("Text1");
textViewParams1.gravity=Gravity.CENTER;
textViewParams1.setMargins(60, 20, 40, 10);
textViewLayout.addView(chooseColorTextView, textViewParams1);
LinearLayout.LayoutParams textViewParams2 = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
TextView TextView2=new TextView(this);
TextView2.setText("Text2");
int width=getWindowManager().getDefaultDisplay().getWidth();
textViewParams2.gravity=Gravity.CENTER;
textViewParams2.setMargins((width/2), 20, 40, 10);
textViewLayout.addView(strokeWidthTextView, textViewParams2);
parentlinearLayout.addView(textViewLayout, textViewLayoutParams);
In the next linear layout, I have added the 4 buttons,seekbar and image view. But facing problems in alignment.
I advise to create complex layout that must be rendered on different screen sizes in XML rather than programmatically, so you can have two different main.xml in res/layout and in res/layout-large and the system would pick up the correct one depending on screen size.
Use layout_weight and weightSum in XML:
<LinearLayout android:weightSum="1" android:layout_width="match_parent" android:layout_height="wrap_content">
<!-- First column -->
<LinearLayout android:layout_weight=".5" android:layout_width="0dp" android:layout_height="wrap_content"> ... </LinearLayout>
<!-- Second column -->
<LinearLayout android:layout_weight=".5" android:layout_width="0dp" android:layout_height="wrap_content"> ... </LinearLayout>
</LinearLayout>
This will produce a dynamically resizing 2 column layout. If you want the divide shorter or longer, change .5 to .3 and .7 for a 30/70% split etc.
Please read more about wrap_content and other android controls. Also read about dpi of tablets. Due to resolution appearance changes.
Why don't you use a TableLayout ? its the one you need to manage cells alignement:
All that you need is in the span attribute to make cells use multiple columns.
TableLayout myLayout = new TableLayout(myContext);
TableRow row1 = new TableRow(myContext);
TableRow.LayoutParams layouparams1 = new TableRow.LayoutParams(TableRow.LayoutParams.FILL_PARENT,TableRow.LayoutParams.WRAP_CONTENT);
layouparams1.span = 4;
row1.setLayoutParams = layouparams1 ;
TableRow.LayoutParams layouparams2 = new TableRow.LayoutParams(TableRow.LayoutParams.FILL_PARENT,TableRow.LayoutParams.WRAP_CONTENT);
layouparams2.span = 2;
TableRow row2 = new TableRow(myContext);
row2.setLayoutParams = layouparams2 ;
//then create and add your childs to each row :
...
row1.addView(text1);
row1.addView(text1);
row1.addView(button1);
row1.addView(button2);
row1.addView(button3);
row1.addView(button4);
row1.addView(seekbar);
row1.addView(imageView);
myLayout.addView(row1);
myLayout.addView(row2);
also consider adding layout_weight on children to manage the space they left to each other.
I have one TextView with text and an image in it. To let it work I set a SpannableString to that TextView as below. My image is shown correctly but the text will be bottom aligned with the image however the gravity of the TextView is center_vertical. I know I can solve this easily with a separate TextView and ImageView but, I want to solve it with 1 TextView as it is part of the text and the image can be everywhere in the text.
ss = new SpannableString(getString(R.string.MyString) + " $");
ss.setSpan(new ImageSpan(ctx, R.drawable.myIcon), ss.length() - 1, ss.length(), 0);
tv.setText(ss);
My TextView will look like
<TextView
android:id="#+id/myTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical" />
Instead of a spannable textview its better if you would use a CoupoundDrawable in android TextView. This link has answers on how to use it.
I wanted to post an image to describe this problem, but apparently I don't have enough of a reputation with stackoverflow yet, so I'm going to try to describe what I am trying to accomplish.
I have a TableLayout with 5 columns. They consist of a company name, a job number, a last name, a graphic vertical divider, and a right arrow button. I would like the divider and right arrow button to be right justified against the right side of the screen. I would like column 2 (the job number) to expand large enough to hold the entire number without wrapping. I would like columns 1 (company name) and 3 (last name) to fill in the rest of the table and use ellipses if they are too big (no text wrapping). My table is built programmatically.
Currently, whenever the company name gets too long, the divider and right arrow get pushed off the right side of the screen.
Here is my layout.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView android:id="#+id/searchResultsFoundTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dp"
android:text="#string/searchResultsLabel"/>
<ScrollView android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TableLayout android:id="#+id/searchResultsTableLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="10dp"
android:stretchColumns="1"
android:shrinkColumns="0,2" />
</ScrollView>
</LinearLayout>
Here is my code to build the table:
TableLayout table = (TableLayout)findViewById(R.id.searchResultsTableLayout);
for (JobBase job : jobList) {
TableRow row = new TableRow(this);
row.setLayoutParams(new TableRow.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
row.setPadding(5, 10, 5, 20);
table.addView(row);
TextView customerNameTextView = new TextView(this);
customerNameTextView.setText(job.getCustomerName());
customerNameTextView.setEllipsize(TextUtils.TruncateAt.END);
customerNameTextView.setTextSize(FONT_SIZE);
customerNameTextView.setPadding(10, 5, 10, 0);
row.addView(customerNameTextView);
TextView jobNumberTextView = new TextView(this);
jobNumberTextView.setText(job.getJobNumber());
jobNumberTextView.setTextSize(FONT_SIZE);
jobNumberTextView.setPadding(10, 5, 10, 0);
row.addView(jobNumberTextView);
TextView crewLeaderTextView = new TextView(this);
crewLeaderTextView.setText(job.getCrewLeader().getLastName());
crewLeaderTextView.setEllipsize(TextUtils.TruncateAt.END);
crewLeaderTextView.setTextSize(FONT_SIZE);
crewLeaderTextView.setPadding(10, 5, 10, 0);
row.addView(crewLeaderTextView);
ImageView dividerImageView = new ImageView(this);
dividerImageView.setImageDrawable(getResources().getDrawable(R.drawable.btn_med_hl_div_white));
dividerImageView.setPadding(10, 10, 10, 0);
row.addView(dividerImageView);
Button rightArrowButton = new Button(this);
rightArrowButton.setBackgroundDrawable(getResources().getDrawable(R.drawable.right_arrow_button));
rightArrowButton.setPadding(10, 0, 10, 0);
rightArrowButton.setOnClickListener(new RowSelectedAction(row));
row.addView(rightArrowButton);
row.setOnClickListener(new RowSelectedAction(row));
}
Any help would be much appreciated.
I was able to fix this by adding a weight through LayoutParams to the first column:
TextView customerNameTextView = new TextView(this);
customerNameTextView.setText(job.getCustomerName());
// --- Added this statement
customerNameTextView.setLayoutParams(new TableRow.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1f));
// ---
customerNameTextView.setEllipsize(TextUtils.TruncateAt.END);
customerNameTextView.setTextSize(FONT_SIZE);
customerNameTextView.setPadding(10, 5, 10, 0);
row.addView(customerNameTextView);
The first column now expands and contracts and the divider and button are always right justified. Sometimes the customer name is ellipsized and other times the name wraps, but that doesn't matter to me as long as the column sizes correctly.