I have 2 classes: MainActivity and CustomView. I have an XML layout with this CustomView.
I want to access all my MainActivity variables from my CustomView class and also to modify them, I tried to get the context but it didn't work.
MainActivity class:
MyCustomView customV;
int myVar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_page);
customV = (MyCustomView) findViewById(R.id.view2);
myVar = 5;
}
MyCustomView class:
public class MyCustomView extends TextView {
public MyCustomView(Context context) {
super(context);
init();
}
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
context.myVar = 7 //this is what I'm trying to do...
I also tried getContext which didn't work.
By trying to access variables from your Activity directly in your TextView subclass, you introduce tight coupling between you subclass of Actity and your custom TextView, which essentially hinders the reusability of your custom TextView because it can then only be used in that type of Activity, using it in another layout would break everything. Basically, I would say it's bad design and would not recommend that approach.
You could simply add a method to your custom TextView, and use the variable there :
public class MyCustomView extends TextView {
// your code
public void setVariable(int myInt){
//use the int here, either set a member variable
//or use directly in the method
}
}
and in your Activity
customV = (MyCustomView) findViewById(R.id.view2);
customV.setVariable(5);
Best way to do so is,
public class MyCustomView extends TextView {
private MainActivity mActivity;
public void setActivity(MainActivity activity) {
mActivity = activity;
}
public MyCustomView(Context context) {
super(context);
init();
}
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
}
Instantiate,
customView = (MyCustomView) findViewById(R.id.view2);
customView.setActivity(this);
Access variable inside functions in MyCustomView,
mActivity.myVar = 10;
If you don't care about the fact that you are tightly coupling your two classes, then the only thing you need to do is typecast your "context" variable to MainActivity. Something like:
((MainActivity) context).myVar = 5;
will work. But you really should consider an alternate design that only loosely couples your classes.
or make the variable static and use it like this.
MainActivity.myVar=7;
or if you want to initialize in the custom view depend on a variable from the MainActivity then do it like that in the custom view.
private int myVar;
public void init(int myVar) {
this.myVar = myVar;
invalidate();
in MainActivity.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_page);
customV = (MyCustomView) findViewById(R.id.view2);
myVar = 5;
customV.init(myVar);
}
i hope this help you.
Related
I am trying to do "a custom font type button" in Android Studio with Java. I have some font types(Simonetta_regular, Simonetta_black, Simonetta_black_italic, Simonetta_italic) and I have 1 button and 1 textView. I want the font type of my textview to change when I click the button. I think if I put to a list my font types, I can do it. How can I do this?
there is many way, one of them is this one:
TextView textview = (TextView) findViewById(R.id.textview);
Typeface tf= Typeface.createFromAsset(getAssets(),"fonts/Tahoma.ttf");
textview.setTypeface(tf);
but if u want to set font by default, u can use this:
public class MyButton extends Button {
public MyButton(Context context) {
super(context);
init();
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
if (!isInEditMode()){
Typeface tf = Typeface.createFromAsset(getContext().getAssets(),"fonts/Tahoma.ttf");
this.setTypeface(tf);
}
}
}
I created some custom component based on ConstraintLayout in Android Studio. First I created base abstract class called MyButton where I do some basic stuff (e.g. get references to my components). Next I created derived class called MySpecialButton that extends MyButton, but I have strange behavior when I attach onClickListener to my Button, that is a part of my custom component, and call method that modify element (reference) that exists only in MySpecialButton from onClickListener.
In a present code, when i try call setImage() from onClickListener, this end up with log: E/NULL: ImageView reference is null! which means that from point of view onClickListener, reference vImageViev is null, however it is initialized in inflateView call. But when I call setImage() not from onClickListener but directly from init() method after inflateView(R.layout.my_special_button) everything is OK.
Also when I move protected ImageView vImageView = null; declaration from MySpecialButton to MyButton everything is OK.
This is my MyButton class:
public abstract class MyButton extends ConstraintLayout
{
protected Context context = null;
protected View rootView = null;
protected Button vButton = null;
protected Switch vSwitch = null;
public MyButton(Context context)
{
super(context);
this.context = context;
init();
}
public MyButton(Context context, AttributeSet attrs)
{
this(context);
}
protected abstract void init();
protected void inflateView(int res)
{
rootView = inflate(context, res, this);
vButton = (Button)rootView.findViewById(R.id.vButton);
vSwitch = (Switch)rootView.findViewById(R.id.vSwitch);
}
}
and this is my MySpecialButton class:
public class MySpecialButton extends MyButton
{
protected ImageView vImageView = null;
public MySpecialButton(Context context)
{
super(context);
}
public MySpecialButton(Context context, AttributeSet attr)
{
this(context);
}
#Override
protected void inflateView(int res)
{
super.inflateView(res);
vImageView = (ImageView)rootView.findViewById(R.id.vImageView);
}
protected void init()
{
inflateView(R.layout.my_special_button);
vButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
setImage();
}
});
}
protected void setImage()
{
if(vImageView == null)
Log.e("NULL", "ImageView reference is null!");
else
vImageView.setImageResource(R.drawable.ic_window);
}
}
What's going on? What I should do to be able call setImage() from onClickListener without null reference?
I think you are doing wrong super calls in your constructors:
This
public MySpecialButton(Context context, AttributeSet attr)
{
this(context);
}
Should be:
public MySpecialButton(Context context, AttributeSet attr)
{
super(context, attr);
}
Same for the other class. And move your custom init in a different function you call from each constructor.
thats because the setOnClickLisnter is called for the base class(which is ConstraintLayout) since you are not override it in the sub-class where the ImageView is not accessible.
try this:
public abstract class MyButton extends ConstraintLayout
{
protected Context context = null;
protected View rootView = null;
protected Button vButton = null;
protected Switch vSwitch = null;
//...
#Override
public void setOnClickListener(#Nullable OnClickListener l) {
vButton.setOnClickLisnter(l);
}
}
I need to know when the user scroll up or down. I managed to achieve that but now I am stuck getting the result back to my main class where I need it. Specifically I don't know how to pass the results to an interface I created.
Here is the error I get:
Attempt to invoke interface method 'void
com.app.android.interfaces.ScrollDirection.Down(int)' on a
null object reference
And here is my custom ScrollView:
public class CustomScrollView extends ScrollView {
private ScrollDirection scrolldirection;
public CustomScrollView(Context context) {
super(context);
scrolldirection = (ScrollDirection) context;
}
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onScrollChanged(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY);
if(scrollY<oldScrollY){
scrolldirection.Down(1);
}else{
scrolldirection.Down(-1);
}
}
public interface ScrollDirection{
public void Down(int direction);
}
}
you need to add this line scrolldirection = (ScrollDirection) context; inside every constructor
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
scrolldirection = (ScrollDirection) context;
}
public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
scrolldirection = (ScrollDirection) context;
}
To allow Android Studio to interact with your view, at a minimum you must provide a constructor that takes a Context and an AttributeSet object as parameters
Docs link
Update : The recent issue was the implementation of CustomScrollView inside Fragment but Fragment do not have their context. To implement this ,make parent Activity implements the ScrollDirection and make some function in Fragment and call them from Activity's Down function.
So I am using MPAndroidChart LineCharts which means in XML I define it this way:
<com.github.mikephil.charting.charts.LineChart
android:id="#+id/line_chart"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
However I am trying to use this chart using various default settings and so on, so I made a custom class to try to extend it:
public class MyLineChart extends com.github.mikephil.charting.charts.LineChart {
private Context mContext;
public MyLineChart(Context context) {
super(context);
mContext = context;
}
//...
And so elsewhere in my code when I want to use it, I have:
private MyLineChart mChart;
...
mChart = new MyLineChart(getActivity());
mChart = (MyLineChart) findViewById(R.id.line_chart);
And it all seems to compile fine, but then it throws a runtime error because it says I cannot convert the LineChart to MyLineChart.
To make it possible using MyLineChart in xml, you need define two more constructors there, like:
public class MyLineChart extends com.github.mikephil.charting.charts.LineChart {
private Context mContext;
public MyLineChart(Context context) {
super(context);
mContext = context;
}
public MyLineChart(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
public LineChart(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
}
// ...
}
I created a custom RelativeLayout and I want to populate it with a design from an xml file, is it possible?
My code:
This is the onCreate from my main activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new CustomRelativeLayout(this));
getLayoutInflater().inflate(R.layout.three_items_list_row, null, false);
}
Just call addView for your custom RelativeLayout instance,
I must say it not a very good coding because you add a Layout level
You need to modify your class to this:
class CustomRelativeLayout{
public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyle){
super(context,attrs,defStyle);
init();
}
public CustomRelativeLayout(Context context, AttributeSet attrs){
super(context,attrs);
init();
}
public CustomRelativeLayout(Context context){
super(context);
init();
}
private void init(){
LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
View v = inflatet.inflate(R.layout.three_items_list_row, this, false);
addView(v);
}
}