How do I set up a constructor in a custom TextView to be able to pass text from a fragment?
In other words, I'm confused how to send text from my fragment (Fragment1) to the custom view (View1):
public class View1 extends TextView {
//constructors:
public View1(Context context, AttributeSet ats, int ds) {
super(context, ats, ds);
init();
}
public View1(Context context) {
super(context);
init();
}
public View1(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
...
canvas.drawText(myString, margin1, margin2, paint); //myString is from Fragment1
....
}
I asked a similar question here, but didn't really get much help. Example code would go a long way towards clearing up my confusion. Thanks in advance!
You are extending a TextView anyway. As A--C mentioned, you can use getText(), as well as setText() to get and set the text.
In your context, I am not sure if it is a good idea to use TextView to implement your custom view/widget. View might be a better starting point, as TextView carries all kind of stuff around for formatting, icon/drawable display, click/button logic etc.
You need to define the standard constructors if you want to be able to have the system instantiate/inflate your components from an XML layout. Then you can use standard getters/setters for your data, same way as all other controls do it.
If you instantiate your widget/view yourself (in your code), you are free to define whatever constructors you want to (I believe).
Related
I just get going on drawing, canvas, basic animations but have stumbled upon this annoying issue:
I have a CustomView
public class CustomView extends View{
//
//Edited code ****************************
bool dir; // true -- right-to-left, false -- left-to-right
public void setDirection(bool b)
this.bool = b
// ****************************************
public CustomView(Context context) {
super(context);
...
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs)
...
}
...
//stuff for animation
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
...
}
...
and inside I have created a little animation, basically something flying from right to left over and over again.
Now, let's say I wanted to have 2 of these views in my layout. But on the second one, stuff should fly from left to right.
Is it possible to somehow pass this "parameter" to the Custom view? or do I really have to create the exact same class and change a plus sign to a minus sign and make it thereby a new class. This would mean animations created by extending view are not tunable at all.
If the latter is the case, then is there a better way to have tunable animations?
Is it possible to somehow pass this "parameter" to the Custom view?
Step #1: Add a field to your custom view to hold your animation
Step #2: Add a setter method to populate the field
Step #3: Call that setter method from something (activity, fragment, etc.) to tell it what animation to use
Im trying to create a sort of HUD overlay for Google Cardboard.
The HUD needs to be duplicated (one for each eye). A simplistic solution would be to manually copy all the XML elements into another view but giving them different names. This feels like a bad approach since it involves lots of code duplication.
So i came up with the following solution for a ViewGroup with is supposed to render everything two times:
public class StereoView extends FrameLayout {
private static final String TAG = StereoView.class.getSimpleName();
public StereoView(Context context) {
super(context);
init(context);
}
private void init(Context context) {
testPaint.setColor(Color.RED);
}
private Paint testPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right/2, bottom);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
canvas.translate(getWidth() / 2, 0);
super.dispatchDraw(canvas);
canvas.restore();
super.dispatchDraw(canvas);
}
public StereoView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public StereoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public StereoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
}
The first problem is that neither dispatchDraw or onDraw is called except from one or two times. It is not called when child views are invalidated.
The second problem is that background on elements which has a with of MATCH_PARENT renders outside the ViewGroups inner bounds:
200DP width
MATCH_PARENT
Is this approach hoping for too much, or am i thinking wrong? Creating a completely custom view to handle complex layouts and images seems like lots of work while copying my layout seems like bad design.
You say:
A simplistic solution would be to manually copy all the XML elements
into another view but giving them different names. This feels like a
bad approach since it involves lots of code duplication.
Actually you can go ahead and use the <include> tag. All you need to do is create a layout that contains all the views that you are going to show to a single eye. Then in your main layout you have to <include> this layout twice, one for the left eye and the other for the right eye.
You might wonder, if this is the case then how can i use findViewById() on this main layout, since now there will be two views with the same id. Well, you can fix that by doing it as follows. Let's say you have created the eye.xml layout. Then your main_layout should look like below.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<include
android:id="#+id/leftEye"
layout="#layout/eye" />
<include
android:id="#+id/rightEye"
layout="#layout/eye" />
</LinearLayout>
When you do the findViewById() in your code, you could do that as follows:
RelativeLayout leftEye = (RelativeLayout)findViewById(R.id.leftEye);
ImageView iv = (ImageView)leftEye.findViewById(R.id.something);
You need write a simple method in your activity where you just pass the leftEye or rightEye as a parameter and perform all code in this method. This lets you perform UI changes in leftEye and rightEye simultaneously.
In the future, you could write a custom View in which you could just inflate the eye.xml. That would modularize your idea.
This is my thoughts to your problem.
A ViewGroup hosts Views; any xml layout are Views, so extend a ViewGroup of your choice, either LinearLayout ,Framelayout-(i prefer), and in your initialisation process, inflate your Layout twice and add them as Views later you can research on how to use onLayout() to position your Views in your preferred Location.
And what ever you call a View 1, View 2 needs to be onboard, you can bind the two, using any approach you want, interfaces or beans
Note
you create one layout and inflate it twice. which will give you two separate View objects, hence this won't be code duplication as its more of
Elltz _20yearElltz = new Elltz(20),_21yearElltz = new Elltz(21);
Hope it helps
I have a lot of views using one and the same color as a background. I want to change the color of all views when I receive a call from the server programmatically. I don't want to call for every view
view.setBackgroundColor(new color);
Is there a way to change a color code that is in colors.xml.
Short answer: No, you can't. The resources are defined at compile time.
See this question for a similar case: How can I programmatically change the value of a color in colors.xml?
You can't replace the value of the color in the xml file. But you
can create different themes which are used in your application and
change the theme dynamically
See this tutorial:
http://www.developer.com/ws/android/changing-your-android-apps-theme-dynamically.html
What I end up doing is create a custom class that sets the color form preference. And use this class everywhere I want to change the color. And next time the view is drawn it gets the new color. Something like this:
public class ColoredToolbar extends android.support.v7.widget.Toolbar {
public ColoredToolbar(Context context) {
super(context);
setBackgroundColor(context);
}
public ColoredToolbar(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(context);
}
public ColoredToolbar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setBackgroundColor(context);
}
private void setBackgroundColor(Context context) {
int color = PreferenceHelper.getToolBarColor(context, Preferences.PREF_TITLE_BAR_COLOR_KEY);
this.setBackgroundColor(color);
}
}
I have a custom view, and I want to use RoboGuice to get views references.
I used this example:https://github.com/roboguice/roboguice/wiki/Your-First-Injection-into-a-Custom-View-class
I tried both options (v3, v3.1), but it does not seem to work (in onFinishInflate, my members are null)
In case it matters, my custom view inherits from a base custom view with a generic type.
Does anyone know why can this happen?
Try adding a call to injectViewMembers, after the injectMembers, which takes care of non-view injections. Not sure why it is not documented and in the sample code.
public ContactView(Context context, AttributeSet attrs) {
super(context, attrs);
this.attrs = attrs;
inflate(context,R.layout.contact_view, this);
if (!isInEditMode()) {
RoboGuice.getInjector(getContext()).injectMembers(this);
RoboGuice.getInjector(getContext()).injectViewMembers(this);
}
}
I have a Scrollview and I have the attribute android:clickable="true" and android:autoLink="all".
I have a string for the ScrollView, and the emails, tel numbers etc, appear and are correctly clickable.
However, The string contains other numbers, such as Years, which also appear clickable and I don't want this; how can I stop this from happening?
Don't use autoLink="all", use the ones you need.
android:autoLink="web|email|phone" will probably cover your use cases.
The clickable="true" on the ScrollView isn't needed for this; rather you should set the autoLink attribute on the TextViews themselves; perhaps extracting a style if you have other common properties.
Add the new Linkify class to your project. From a place that you have access to the TextView (e.g. the Activity):
TextView myTextView = // get a reference to your textview
int mask = Linkify.ALL;
Linkify.addLinks(myTextView, mask);
The addLinks(TextView, int) method is static, so you can use it without creating an instance of Linkify. The return value (boolean) indicates whether something was linkified, but you probably don't need this information, so we don't bother with it.
You'll need to ensure that you don't put the autoLink attribute on the TextViews, otherwise the setText(...) implementations will still linkify years (unless you completely override the setText(...) implementations without calling super.setText(...))
For extra brownie points, you can create a subclass of TextView which will do the linkify for you when you set text on it:
public class AutoLinkifyTextView extends TextView {
public AutoLinkifyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoLinkifyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void setText(String text) {
super.setText(text);
parseLinks();
}
#Override
public void setText(int stringRes) {
super.setText(stringRes);
parseLinks();
}
private void parseLinks() {
Linkify.addLinks(this, Linkify.ALL);
}
}
For top marks of course, you'd read the attributes from the attrs and use the correct mask from the XML attributes, but I'd prefer to get rid of that option and do it here.