I was creating my textview which use as a header in my MainActivity file and everything was okay until I thought I'd better move the code to another class.
While it works and displays the text however when I try to animate it it doesn't work.
The code I was using is in the init() method.
The code is very simple and I'm pasting it here:
public class TextViewHeader extends TextView {
private static final String TAG = "TextViewHeader".toUpperCase();
private Context context;
private FrameLayout frameLayoutWhiteTowerContainer;
private String text;
private int whiteTowerContainerHeight;
private int tower_height;
public TextViewHeader(Context context) {
super(context);
}
public TextViewHeader(Context context, String text, FrameLayout frameLayoutWhiteTowerContainer,
int whiteTowerContainerHeight, int tower_height) {
super(context);
this.context = context;
this.text = text;
this.frameLayoutWhiteTowerContainer = frameLayoutWhiteTowerContainer;
this.whiteTowerContainerHeight = whiteTowerContainerHeight;
this.tower_height = tower_height;
init();
}
public TextViewHeader(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init() {
TextView textView = new TextView(context);
textView.setText(text);
textView.setTextSize(25);
textView.setTextColor(Color.parseColor("#FF545454"));
Typeface typefaceCondensed = Typeface.create("sans-serif-condensed", Typeface.BOLD);
textView.setTypeface(typefaceCondensed);
FrameLayout.LayoutParams tv_header_params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
int topMargin = whiteTowerContainerHeight / 2 - tower_height / 2 - 100;
tv_header_params.topMargin = topMargin;
tv_header_params.gravity = Gravity.CENTER_HORIZONTAL;
textView.setLayoutParams(tv_header_params);
frameLayoutWhiteTowerContainer.addView(textView, tv_header_params);
}
}
The code in MainActivity is :
tvHeader = new TextViewHeader(MainActivity.this, "TOWER", flWhiteTowerContainer,
whiteTowerContainerHeight, tower_height ); // create inside onCreate method
tvHeader.animate().y(515).setDuration(1500).start(); //and the animation happens later onMapReady
You are starting an animation before the TextViewHeader is laid out.
Try:
tvHeader = new TextViewHeader(MainActivity.this, "TOWER", flWhiteTowerContainer,
whiteTowerContainerHeight, tower_height );
tvHeader.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
// Layout complete but not drawn yet
tvHeader.getViewTreeObserver().removeOnPreDrawListener(this);
tvHeader.animate().y(515).setDuration(1500).start();
return false;
}
});
The problem is that I'm implementing the TextView but I don't use it. Instead I just create another TextView in the class and I use this instead of my class.
In other words the code :
TextView textView = new TextView(context);
shouldn't exist and just use this to setText, setTextSize, color, etc.
this.setText(text);
this.setTextSize(25);
this.setTextColor(Color.parseColor("#FF545454"));
Related
I am adding ImageView dynamically inside a RelativeLayout programmatically but I also need to attach remove icon/button with onClick handler with those dynamic ImageViews. So that if I click on any of the delete icon related to that dynamic image view will be deleted.
Here is my code where I am adding dynamic image views inside the layout:
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
final ImageView iv = new ImageView(this);
iv.setId(id);
iv.setPadding(2, 2, 2, 2);
iv.setImageBitmap(BitmapFactory.decodeResource(
getResources(), (int)iconTable[id]));
iv.setScaleType(ImageView.ScaleType.MATRIX);
iv.setLayoutParams(lp);
rl.addView(iv);
I'd recommend to create a custom component. Something like this:
public class DeletableImageView extends LinearLayout {
private ImageView mImage;
private Button mButton;
DeletableImageListener mListener
public DeletableImageView(Context context) {
super(context);
init(context);
}
public DeletableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DeletableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
setOrientation(LinearLayout.VERTICAL);
inflate(context, R.layout.deletable_image, this);
initViews();
}
private void initViews() {
mImage= (ImageView) findViewById(R.id.image);
mButton= (Button) findViewById(R.id.delete_button);
mButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
if (mListener != null) {
mListener.deleteMe(DeletableImageView.this);
}
}
}
}
public void setListener(DeleteableImageListener listener) {
mListener = listener;
}
public interface DeletableImageListener {
void deleteMe(DeletableImageView me);
}
public void setImage(Drawable drawable) {
mImage.setBackground(drawable);
}
}
R.layout.deletable_imageis a normal xml-layout with <merge> as root element (since the DeletableImageView already is a LinearLayout. Within the merge-Tag you have the ImageView and the Button.
<merge xmlns="...">
<ImageView android:id="#+id/image" .../>
<Button android:id="#+id/delete_button" .../>
</merge>
In your code you don't add an ImageView, but your custom component and set the Listener as callback, so you can remove the custom component again.
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl);
final DeletableImageView div = new DeletableImageView(this);
div.setImage(...); // add this method to DeletableImageView
div.setListener(this);
// either implement these in your custom component or directly set it in the <ImageView> in R.layout.deletable_image
div.setScaleType(...);
div.setPadding(2, 2, 2, 2);
rl.addView(div);
The last step is to implement deleteMe(DeletableImageView me). You have to hold a reference to your RelativeLayout and it should work by just calling rl.removeView(me);
I have a MtxVideoView class which contains textview and surfaceview. The MtxVideoView class extends FrameLayout. I want to change size of MtxVideoView . How can do that ?
Following the code of special view
public class MtxVideoView extends FrameLayout implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener,
VideoControllerView.MediaPlayerControl, MediaPlayer.OnErrorListener {
private Context mContext;
private SurfaceHolder mSurfaceHolder;
private SurfaceView mSurfaceView;
private MediaPlayer mPlayer;
private VideoControllerView controller;
private TextView mMessage;
private boolean mbSrcAvailable = false;
private boolean mbSurfaceCreated = false;
private String mSource = "";
private String mUserName = "";
private String mPassword = "";
private boolean mbFullscreen = false;
private FullScreenListener mFullScreenListener;
private int mCount = 0;
static interface FullScreenListener {
void onFullScreen( View view, boolean bFullScreen);
}
public void setFullScreenListener( FullScreenListener listener ){
mFullScreenListener = listener;
}
public MtxVideoView(Context context) {
super(context);
mContext = context;
mbFullscreen = false;
Init();
}
public MtxVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
Init();
}
public MtxVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
Init();
}
private void Init(){
mSurfaceView = new SurfaceView(mContext);
mSurfaceView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT ));
addView(mSurfaceView);
mMessage = new TextView(mContext);
mMessage.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT ));
mMessage.setGravity(Gravity.CENTER);
mMessage.setTextColor(Color.WHITE);
this.addView(mMessage);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
}
}
Try this code.
But you have to run it when view is already measured.
{
LayoutParams param = getLayoutParams();
param.width = 100;
param.height = 200;
requestLayout();
}
When defining in xml use layout_width and layout_hight.
If you are adding dynamically then set layout parameters or add this view with layout parameters to its parent.
I'm creating dinamically a LinearLayout (a custom Class that extends LinearLayout) with a RadioGroup inside it. I'm adding RadioButtons dinamically also. This LinearLayout class is used in several Activities and Fragments.
The strange behaviour is that the second time I add LinearLayout, when OnCheckedChanged is called, a get an index that doesn't exists in my current RadioGroup. I't seems that every time I create a new Instance of my LinearLayout, RadioGroup thinks that RadioButtons added previously are still there.
For example, if I create a custom LinearLayout and I add four items and after that I create another LinearLayout (in other Activity) with other 4 items, when I click in the first item (on the second Activity), I get a 5 as clicked item position.
This is my custom LinearLayout class:
public class AgrupacionConmutadorLayout extends LinearLayout{
private static final String TAG = "AgrupacionConmutadorLayout";
private int[] mColorFromLevel = {R.color.inspeccion_aparato_agrupacion_color_level_1, R.color.inspeccion_aparato_agrupacion_color_level_2,
R.color.inspeccion_aparato_agrupacion_color_level_3, R.color.inspeccion_aparato_agrupacion_color_level_4, R.color.inspeccion_aparato_agrupacion_color_level_5};
private Context mContext;
private LinearLayout dataContainer;
private TextView mTitle;
private RelativeLayout mSubAgrupacionesContainer;
private LinearLayout mDataAndSubAgrupacionesContainer;
private RadioGroup mConmutadorContainer;
private ArrayList<View> mLayoutsDataContained = new ArrayList<View>();
private int mLevel;
private LinearLayout mTitleContainer;
private InspeccionesFormWidgetReceiver mModificationReceiver;
private boolean isEdicion;
public AgrupacionConmutadorLayout(Context context) {
super(context);
this.mContext = context;
init(null, 0);
}
public AgrupacionConmutadorLayout(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init(attrs, 0);
}
public AgrupacionConmutadorLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
init(attrs, defStyle);
}
private void init(AttributeSet attrs, int defStyle) {
dataContainer = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.ins_agrupacion_conmutador_container, this);
mTitle = (TextView) dataContainer.findViewById(R.id.ins_agrupacion_container_title);
mSubAgrupacionesContainer = (RelativeLayout) findViewById(R.id.rl_ins_subagrupacion_container);
mConmutadorContainer = (RadioGroup) findViewById(R.id.ins_agrupacion_conmutador_radio_group);
mDataAndSubAgrupacionesContainer = (LinearLayout) findViewById(R.id.ll_ins_data_and_subagrupacion_container);
mTitleContainer = (LinearLayout) findViewById(R.id.ll_ins_agrupacion_container_title);
mConmutadorContainer.removeAllViews();
mConmutadorContainer.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int pos) {
Log.d(TAG, "onCheckedChanged Clicked pos: " + pos);
Log.d(TAG, "onCheckedChanged RadioGroup size: " + radioGroup.getChildCount());
Log.d(TAG, "onCheckedChanged " + mLayoutsDataContained.size());
//OnCheckedChanged comienza a devolver en 1, al ArrayList en 0
for (int i = 1; i < mLayoutsDataContained.size() + 1; i++) {
if (i == pos) {
mLayoutsDataContained.get(i - 1).setVisibility(View.VISIBLE);
} else {
mLayoutsDataContained.get(i - 1).setVisibility(View.GONE);
}
}
}
});
}
public void initialice(AgrupacionSios agrupacionSios, InspeccionesFormWidgetReceiver modificationReceiver, boolean isEdicion) {
this.mModificationReceiver = modificationReceiver;
this.isEdicion = isEdicion;
mTitle.setText(agrupacionSios.getTitle());
mTitle.setTextColor(mContext.getResources().getColor(mColorFromLevel[agrupacionSios.getLevel()]));
if (agrupacionSios.isOcultarContenedor()) mTitleContainer.setVisibility(View.GONE);
if (agrupacionSios.getNumOfSons() > 0) {
drawSubAgrupaciones(agrupacionSios);
}
this.refreshDrawableState();
}
private void drawSubAgrupaciones(AgrupacionSios agrupacionSios) {
ViewGroup.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
ArrayList<AgrupacionSios> agrupaciones = agrupacionSios.getAgrupacionesHijos();
Iterator itAgr = agrupaciones.iterator();
while (itAgr.hasNext()) {
AgrupacionSios agrupacionHija = (AgrupacionSios) itAgr.next();
if (agrupacionHija.getNumOfLevels() > 0 || agrupacionHija.getNumOfSons() > 0) {
switch (agrupacionHija.getTipoSubAgrupaciones()) {
case CONMUTADOR:
AgrupacionConmutadorLayout v = new AgrupacionConmutadorLayout(mContext);
v.initialice(agrupacionHija, mModificationReceiver, isEdicion);
mSubAgrupacionesContainer.addView(v, layoutParams);
mLayoutsDataContained.add(v);
break;
case COLUMNAS:
AgrupacionColumnasLayout vCol = new AgrupacionColumnasLayout(mContext);
vCol.initialice(agrupacionHija, mModificationReceiver, isEdicion);
mSubAgrupacionesContainer.addView(vCol, layoutParams);
mLayoutsDataContained.add(vCol);
break;
default:
AgrupacionGenericaLayout vGen = new AgrupacionGenericaLayout(mContext);
vGen.isSonOfConmutador(true);
vGen.initialice(agrupacionHija, mModificationReceiver, isEdicion);
mSubAgrupacionesContainer.addView(vGen, layoutParams);
mLayoutsDataContained.add(vGen);
break;
}
}
//Añadimos el botón de conmutación correspondiente a la subagrupación.
addAgrupacionToConmutadorContainer(agrupacionHija);
}
mConmutadorContainer.check(1);
}
public void setBackgroundColor(int color) {
setBackgroundResource(color);
}
private void addAgrupacionToConmutadorContainer(AgrupacionSios mAgrupacion) {
ViewGroup.LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
RadioButton b = new RadioButton(mContext);
b.setLayoutParams(layoutParams);
b.setText(mAgrupacion.getTitle());
b.setButtonDrawable(android.R.color.transparent);
b.setBackground(mContext.getResources().getDrawable(R.drawable.ins_conmutador_radio_background));
b.setPadding(20,5,20,5);
RadioGroup.LayoutParams params
= new RadioGroup.LayoutParams(mContext, null);
params.setMargins(10, 0, 10, 0);
b.setLayoutParams(params);
mConmutadorContainer.addView(b);
}
}
And this is the way I create AgrupacionConmutadorLayout on Activities & Fragments:
AgrupacionConmutadorLayout vConm = new AgrupacionConmutadorLayout(this);
vConm.initialice(agrupacion, this, isEdicion);
vConm.setVisibility(View.VISIBLE);
mAgrupacionesContainer.addView(vConm, layoutParams);
-----------------SOLUTION---------------------------
Marius answer was the key, I was getting clicked RadioButton id, not his position inside RadioGroup.
Finally I have done it by using tags. I set its order to every RadioButton as a tag:
private void addAgrupacionToConmutadorContainer(AgrupacionSios mAgrupacion) {
ViewGroup.LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
RadioButton b = new RadioButton(mContext);
b.setLayoutParams(layoutParams);
b.setText(mAgrupacion.getTitle());
b.setButtonDrawable(android.R.color.transparent);
b.setBackground(mContext.getResources().getDrawable(R.drawable.ins_conmutador_radio_background));
b.setPadding(20, 5, 20, 5);
RadioGroup.LayoutParams params
= new RadioGroup.LayoutParams(mContext, null);
params.setMargins(10, 0, 10, 0);
b.setLayoutParams(params);
b.setTag(mConmutadorContainer.getChildCount());
mConmutadorContainer.addView(b);
}
And I get that tag in OnCheckedChangeListener:
mConmutadorContainer.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int clickedId) {
View radioButtonClicked = radioGroup.findViewById(clickedId);
if (radioButtonClicked != null) {
Integer pos = (Integer) radioButtonClicked.getTag();
Log.d(TAG, "onCheckedChanged RadioGroup clicked position: " + pos);
for (int i = 0; i < mLayoutsDataContained.size(); i++) {
View view = mLayoutsDataContained.get(i);
if (pos.intValue() == i) {
view.setVisibility(View.VISIBLE);
} else view.setVisibility(View.GONE);
}
}
}
});
You must have misread the API. Second parameter is NOT position. It's the id, of the button. There are several solutions to your problem.
Adding id, based on position:
//not recommended way, as activity.findViewById uses this id, I GUESS something wrong may happen
private int currId;
...
b.setId(currId);
currId++;
container.addView(b);
Adding a tag:
//recommended
b.setTag(mAgrupacion);
container.addView(b);
//then...
AgrupacionSios tag = (AgrupacionSios) b.getTag();
//do action based on tag information
Use this.
for (int i = 0; i < mLayoutsDataContained.size(); i++) {
if (i == pos) {
mLayoutsDataContained.get(i - 1).setVisibility(View.VISIBLE);
} else {
mLayoutsDataContained.get(i - 1).setVisibility(View.GONE);
}
}
So i have a custom view called Square which I want to add in a table.
When I replace my squares with text views it works perfectly.
I searched quite a bit online and found that I should call setWillNotDraw(false) in the constructor. I did this to no result.
Here is my class Square:
public class Square extends View
{
private String courseName;
private String className;
private String place;
private Weekdays weekday;
private int hour;
private Paint paint;
public Square(Context context, AttributeSet attrs){
super(context,attrs);
setWillNotDraw(false);
}
public Square(Context context, String courseName, String className, String place, Weekdays weekday, int hour)
{
super(context);
this.courseName = courseName;
this.className = className;
this.place = place;
this.weekday = weekday;
this.hour = hour;
setWillNotDraw(false);
paint = new Paint();
}
public Square(Context context,Weekdays weekdays, int i) {
super(context);
this.weekday = weekdays;
this.hour = i;
setWillNotDraw(false);
paint = new Paint();
paint.setColor(Color.BLACK);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.drawText("Hello I'm a test", 1, 30, paint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
I have tried setting the onMeasure() method to use 10,10 or whatever, but nothing shows up. I don't know if this is relevant to my problem.
The table is made dynamically like this:
public class MainActivity extends Activity {
private Controller controller;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
controller = new Controller(this);
createTable();
}
private void createTable() {
// get a reference for the TableLayout
TableLayout table = (TableLayout) findViewById(R.id.tableLayout1);
/**Create 8 rows*/
for(int i=0;i<Controller.TABLE_ROW_COUNT;i++){
// create a new TableRow
TableRow row = new TableRow(this);
/** create 5 columns*/
for(int j=0;j<Controller.TABLE_COLUMN_COUNT;j++){
Square sq = controller.tableModel.getSquare(Weekdays.values()[j], i);
row.addView(sq, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
// add the TableRow to the TableLayout
table.addView(row,new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
}
Thanks!
What's your target SDK version? If it's >= 11, hardware acceleration is making GPU cache your view. Try calling setLayerType(View.LAYER_TYPE_SOFTWARE, null) in your constructor.
Replace your onMeasure with the following:
public void onMeasure(int wms, int hms){
setMeasuredDimension(MeasureSpec.getSize(wms), MeasureSpec.getSize(hms));
}
The default (super) implementation in View sets its size to 0x0.
You may need to adjust the values to get a nice size depending on the parent.
If Hardware Acceleration is TRUE for your Activity.
Then try disabling the Hardware acceleration for that ImageView.
imageview.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
Worked for me.
Due to margin and padding problems with the regular Button class I've been working on a custom Layout that extends FrameLayout.
I ran into a problem, that the contents of the layout do not get displayed.
As soon as I'm changing this to another e.g. RelativeLayout the contents get displayed.
This is my relevant code:
private static final int COLOR = R.styleable.MyButton_color;
private static final int TEXT = R.styleable.MyButton_text;
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutParams backgroundParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
backgroundParams.gravity = Gravity.FILL;
background = new ImageView(context, null, defStyle);
addView(background, backgroundParams);
text = new TextView(context, null, defStyle);
text.setTypeface(null, Typeface.BOLD);
LayoutParams textParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
textParams.gravity = Gravity.CENTER;
addView(text, textParams);
TypedArray a = context.obtainStyledAttributes(R.styleable.MyButton);
try {
setColor(Color.values()[a.getInteger(COLOR, 0)]);
setText(a.getString(TEXT));
} finally {
a.recycle();
}
}
public void setText(CharSequence text) {
this.text.setText(text);
}
private void setColor(Color color) {
switch (color) {
case ORANGE:
text.setTextColor(getContext().getResources().getColor(R.color.text_blue));
background.setImageResource(R.drawable.button_orange);
break;
case BLUE:
//TODO set colors
break;
}
}
What am I missing on this one?
Extending FrameLayout, this is a special layout which has set a flag on most API versions to not call draw functions.
To overcome this, set the flag to false when constructing:
public MyButton(
...
setWillNotDraw(false);
...
The answer is quite obvious.
LayoutParams backgroundParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
has to be replaced by
LayoutParams backgroundParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
The same applies for textParams, of course.