How to pass variables to custom View before onDraw() is called? - android

What I am trying to achieve:
measure a container View in my layout, mainContainer, that is defined in the XML
pass the mainContainer's width and height to a different custom View before onDraw() is called
I want to pass the width and height so the custom View knows where to draw canvas.drawBitmap using coordinates
The custom view will be programmatically created from code
How can I pass the measured int width and int height to my custom View before onDraw() is called?
Custom View
public class AvatarView extends ImageView {
private Bitmap body;
private Bitmap hat;
public AvatarView(Context context) {
super(context);
init();
}
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
body = BitmapFactory.decodeResource(getResources(), R.drawable.battle_run_char);
hat = BitmapFactory.decodeResource(getResources(), R.drawable.red_cartoon_hat);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(body, x, y, null);
canvas.drawBitmap(hat, x, y, null);
}
}
Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_customize_avatar, container, false);
final RelativeLayout mainContainer = (RelativeLayout) view.findViewById(R.id.main_container);
TwoWayView inventoryList = (TwoWayView) view.findViewById(R.id.inventory);
inventoryList.setAdapter(null);
inventoryList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
}
});
mainContainer.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
// Retrieve the width and height
containerWidth = mainContainer.getWidth();
containerHeight = mainContainer.getHeight();
// Remove global listener
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
mainContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
else
mainContainer.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
return view;
}
XML
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:clickable="true"
android:background="#fff" >
<com.walintukai.lfdate.CustomTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:textStyle="bold"
android:textColor="#fff"
android:textSize="20sp"
android:textAllCaps="true"
android:text="#string/customize_avatar"
android:background="#009BFF" />
<RelativeLayout
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<org.lucasr.twowayview.TwoWayView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/inventory"
style="#style/HorizontalListView"
android:layout_width="match_parent"
android:layout_height="80dp"
android:drawSelectorOnTop="false"
android:background="#f3f3f3" />
</LinearLayout>

What you need to do is add a flag inside your AvatarView that checks if are you going to render this or not in your onDraw method.
sample:
public class AvatarView extends ImageView {
private Bitmap body;
private Bitmap hat;
private int containerHeight;
private int containerWidth;
private boolean isRender = false;
public AvatarView(Context context) {
super(context);
init();
}
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setMeasure(int containerWidth, int containerHeight )
{
this.containerHeight = containerHeight;
this.containerWidth = containerWidth;
}
private void init() {
body = BitmapFactory.decodeResource(getResources(), R.drawable.battle_run_char);
hat = BitmapFactory.decodeResource(getResources(), R.drawable.red_cartoon_hat);
}
public void setRender(boolean render)
{
isRender = render;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(isRender )
{
canvas.drawBitmap(body, x, y, null);
canvas.drawBitmap(hat, x, y, null);
}
}
}
Now it wont render when you dont call setRender and set it to true. And just call setMeasure to pass the value.
First you need to call setMeasure and after you set the measure you then call setRender(true) and call invalidate() to call the onDraw method to render the images

Related

Android Studio: Create Object in custom SwipeButton with attributes from XML

public class SwipeButton extends RelativeLayout {
private ImageView swipeButtonInner;
private float initialX;
private boolean active;
private TextView centerText;
private ViewGroup background;
private Drawable disabledDrawable;
private Drawable enabledDrawable;
private OnStateChangeListener onStateChangeListener;
private OnActiveListener onActiveListener;
private static final int ENABLED = 0;
private static final int DISABLED = 1;
private int collapsedWidth;
private int collapsedHeight;
private LinearLayout layer;
private boolean trailEnabled = false;
private boolean hasActivationState;
public SwipeButton(Context context) {
super(context);
init(context, null, -1, -1);
}
public SwipeButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, -1, -1);
}
public SwipeButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, -1);
}
#TargetApi(21)
public SwipeButton(Context context, AttributeSet attrs, int defStyleAttr, int
defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs, defStyleAttr, defStyleRes);
}
public boolean isActive() {
return active;
}
public void setText(String text) {
centerText.setText(text);
}
public void setBackground(Drawable drawable) {
background.setBackground(drawable);
}
public void setSlidingButtonBackground(Drawable drawable) {
background.setBackground(drawable);
}
public void setDisabledDrawable(Drawable drawable) {
disabledDrawable = drawable;
if (!active) {
swipeButtonInner.setImageDrawable(drawable);
}
}
public void setButtonBackground(Drawable buttonBackground) {
if (buttonBackground != null) {
swipeButtonInner.setBackground(buttonBackground);
}
}
public void setEnabledDrawable(Drawable drawable) {
enabledDrawable = drawable;
if (active) {
swipeButtonInner.setImageDrawable(drawable);
}
}
public void setOnStateChangeListener(OnStateChangeListener
onStateChangeListener) {
this.onStateChangeListener = onStateChangeListener;
}
public void setOnActiveListener(OnActiveListener onActiveListener) {
this.onActiveListener = onActiveListener;
}
public void setInnerTextPadding(int left, int top, int right, int bottom) {
centerText.setPadding(left, top, right, bottom);
}
public void setSwipeButtonPadding(int left, int top, int right, int bottom) {
swipeButtonInner.setPadding(left, top, right, bottom);
}
public void setHasActivationState(boolean hasActivationState) {
this.hasActivationState = hasActivationState;
}
My XML:`
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="#+id/AnswerRelativeLayout"
android:layout_height="70dp"
android:orientation="vertical"
tools:context="com.example.dynamicobj.FragmentMain">
<com.example.dynamicobj.SwipeButton
android:id="#+id/test_btn"
android:layout_width="match_parent"
android:layout_height="70dp"
app:button_background="#drawable/shape_button"
app:button_image_disabled="#drawable/ic_launcher_background"
app:button_image_height="60dp"
app:button_image_width="100dp"
app:has_activate_state="true"
app:initial_state="disabled"
app:inner_text="Termine buchen"
app:inner_text_background="#drawable/shape_rounded"
app:inner_text_bottom_padding="18dp"
app:inner_text_right_padding="200dp"
app:inner_text_color="#android:color/black"
app:inner_text_size="16sp"
app:inner_text_top_padding="18dp" />
</LinearLayout>`
F
ragmentMain:
public class FragmentMain extends Fragment {
Context context;
View rootView;
public FragmentMain() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(false);
}
#Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_main, container, false);
LinearLayout layout = (LinearLayout)
rootView.findViewById(R.id.AnswerRelativeLayout);
SwipeButton button = new SwipeButton(getContext());
layout.addView(button);
return rootView;
}
}
So I got this custom SwipeButton class from Git (com.ebanx.swipebtn.SwipeButton). Now I want to create an Object from SwipeButton with a layout looking like the one from the xml file. Is there any method, where I just can give the new button the prefinished layout without having to use all these Methods in the SwipeButton class? I am going to create the buttons dynamically later on, but all being the same layout. Help pls?
you forgot to add LayoutParams to your button
use below code before adding button into layout
button.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT))
and set your LinearLayout height wrap_content not 70dp

Single custom view multiple shape animation

If a custom view has several shapes, Is it possible to animate only one of them?
For eg: for one of my application, 2 circles, one inner and another outer are drawn on a custom view. While I tried to animate using scale animation, I see that both the circles gets animated where as I need only one of them to.
One of the solution that occurred to me is to have multiple custom views.
But not sure if it is the right way to do it.
Are there alternate better solution to it?
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.test.customanimation.CustomView
android:id="#+id/circular_progress"
android:layout_width="400dp"
android:layout_height="400dp"
android:layout_gravity="center"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="#+id/scale_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Scale Up"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:id="#+id/scale_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="Scale Down"/>
</android.support.constraint.ConstraintLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private CustomView mCustomView;
private Button mScaleUpBtn;
private Button mScaleDownBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCustomView = findViewById(R.id.circular_progress);
mScaleUpBtn = findViewById(R.id.scale_up);
mScaleUpBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mCustomView.scaleUpAnimation(5000);
}
});
mScaleDownBtn = findViewById(R.id.scale_down);
mScaleDownBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mCustomView.scaleDownAnimation(5000);
}
});
}
}
CustomView.java
public class CustomView extends View {
private Paint OuterCirclePaint,InnerCirclePaint;
float mCircleX,mCircleY,mInnerCircleRadius,mOuterCircleRadius;
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomView(Context context, #Nullable AttributeSet attrs, int
defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public CustomView(Context context, #Nullable AttributeSet attrs, int
defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init(){
OuterCirclePaint = new Paint();
OuterCirclePaint.setColor(Color.GREEN);
OuterCirclePaint.setStrokeWidth(20);
OuterCirclePaint.setStyle(Paint.Style.STROKE);
InnerCirclePaint = new Paint();
InnerCirclePaint.setColor(Color.BLACK);
InnerCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
#Override
protected void onDraw(Canvas canvas) {
mCircleX = getWidth()/2;
mCircleY = getHeight()/2;
if(mCircleX < mCircleY) {
mInnerCircleRadius = (getWidth() / 2) - 100;
mOuterCircleRadius = (getWidth() / 2) - 40;
}
else {
mInnerCircleRadius = (getHeight() / 2) - 100;
mOuterCircleRadius= (getHeight() / 2) - 40;
}
canvas.drawCircle(mCircleX,mCircleY,mOuterCircleRadius,OuterCirclePaint);
canvas.drawCircle(mCircleX,mCircleY,mInnerCircleRadius,InnerCirclePaint);
}
public void scaleDownAnimation(int duration){
ScaleAnimation fade_in = new ScaleAnimation(1.0f,0.5f,1.0f,0.5f,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
fade_in.setDuration(duration);
fade_in.setFillAfter(true);
this.startAnimation(fade_in);
}
public void scaleUpAnimation(int duration){
ScaleAnimation fade_out = new ScaleAnimation(0.5f,1.0f,0.5f,1.0f,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
fade_out.setDuration(duration);
fade_out.setFillAfter(true);
this.startAnimation(fade_out);
}
}
You are already overriding onDraw() and providing your own methods to handle the animations. IMO this approach is best for performance, so I'd keep it that way and only switch over to another animation framework, namely Property Animations
In order to redraw only the inner circle during an animation, I'd suggest using ValueAnimator and ValueAnimator.AnimatorUpdateListener for the animations.
Let's introduce some new fields for CustomView
private float scaleFactor = 1f;
private ValueAnimator scaleUpAnimator;
private ValueAnimator scaleDownAnimator;
private ValueAnimator.AnimatorUpdateListener updateListener;
Initialize them as follows
private void initAnimations() {
scaleUpAnimator = ValueAnimator.ofFloat(0.5f, 1.0f);
scaleDownAnimator = ValueAnimator.ofFloat(1.0f, 0.5f);
updateListener = new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleFactor = (float)animation.getAnimatedValue();
CustomView.this.invalidate();
}
};
scaleUpAnimator.addUpdateListener(updateListener);
scaleDownAnimator.addUpdateListener(updateListener);
}
Change the line for the inner circle in onDraw()
canvas.drawCircle(mCircleX, mCircleY, mInnerCircleRadius * scaleFactor, innerCirclePaint);
... and start the animations like this
public void scaleDownAnimation(int duration){
scaleDownAnimator.setDuration(duration);
scaleDownAnimator.start();
}
public void scaleUpAnimation(int duration){
scaleUpAnimator.setDuration(duration);
scaleUpAnimator.start();
}

Programmatically created "Circle Button" not drawing

I have a custom CircleButton class:
public class CircleButton extends ImageView {
private int radius;
private int x;
private int y;
public CircleButton(Context context) {
super(context);
constructorTask();
}
public CircleButton(Context context, AttributeSet attrs) {
super(context, attrs);
constructorTask();
}
public CircleButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
constructorTask();
}
public CircleButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
constructorTask();
}
private void constructorTask() {
x = 300;
y = 300;
radius = 100;
}
#Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
Log.i("Button Logger","Button Pressed");
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, radius, GameView.green);
Log.i("Drawing status", "CircleButton Drawing...");
}
}
I have a single activity. This activity contains a relative layout with a single custom view.
Here is the custom view:
public class GameView extends View {
public static Paint green = new Paint();
public GameView(Context context) {
super(context);
green.setARGB(255,0,255,0);
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
green.setARGB(255, 0, 255, 0);
}
public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
green.setARGB(255, 0, 255, 0);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.i("GameView Draw Status","Drawing...");
Main.testButton.invalidate();
invalidate();
}
}
And here is the activity code:
public class Main extends AppCompatActivity {
public static CircleButton testButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testButton = new CircleButton(getApplicationContext());
makeFullScreen();
RelativeLayout screenLayout = (RelativeLayout) findViewById(R.id.screenLayout);
screenLayout.addView(testButton);
}
private void makeFullScreen() {...}
}
For some reason my testButton is not being drawn. Why is it not being drawn?
EDIT ONE: Here is the XML I have.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"
tools:context="com.example.vroy.customcirclebuttontest.Main"
android:id="#+id/screenLayout">
<com.example.vroy.customcirclebuttontest.GameView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/black"
android:id="#+id/gameScreen" />
</RelativeLayout>
EDIT TWO: I did some further debugging by adding a normal button to the relative layout and it worked fine.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testCircleButton = new CircleButton(getApplicationContext());
makeFullScreen();
testButton = new Button(getApplicationContext());
testButton.setX(100);
testButton.setY(100);
testButton.setText("HELLO WORLD");
RelativeLayout screenLayout = (RelativeLayout) findViewById(R.id.screenLayout);
screenLayout.addView(testCircleButton);
screenLayout.addView(testButton);
Log.i("Button Status","Adding Button To Layout");
}
For some reason by circleButton is not working but a normal button is.
You are not specifying the size of the View (layout_width and layout_height), and thus your view is getting rendered inside a 0px by 0px space and thus invisible.
You can set those programatically using LayoutParams before adding your views to the layout.
For example with absolute size:
testButton.setLayoutParams(new ViewGroup.LayoutParams(100,100));
Although keep in mind the difference between px and dip. You would probably want to set the values using your internal radius attribute instead of harcoding them.

How to add a custom view in another custom view in Android?

I want to create a custom view which should be added in another custom view.
The second view will be a container, so it should be able to contain the first view as its child.
For creating this views I am extending ViewGroup & LinearLayout classes.
Child view class is NodeView
public class NodeView extends LinearLayout
{
private final static String TAG = "NodeView";
private ImageView ivTop;
private ImageView ivBottom;
private Context myContext;
public NodeView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.myContext = context;
setOrientation(LinearLayout.VERTICAL);
setGravity(Gravity.CENTER);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.view_test_multi, this, true);
ivTop = (ImageView) getChildAt(0);
ivBottom = (ImageView) getChildAt(2);
ivTop.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Toast.makeText(myContext, "Top Clicked", Toast.LENGTH_SHORT).show();
}
});
ivBottom.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Toast.makeText(myContext, "Bottom Clicked", Toast.LENGTH_SHORT).show();
}
});
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
}
public NodeView(Context context)
{
this(context, null);
}
}
& the container class is TreeViewGroup
public class TreeViewGroup extends ViewGroup
{
private static final String TAG = "CustomTreeNodeView";
NodeView nodeView;
public TreeViewGroup(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
nodeView = new NodeView(getContext());
addView(nodeView);
}
public TreeViewGroup(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public TreeViewGroup(Context context)
{
this(context, null, 0);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
}
}
& xml layout for node view is view_test_multi.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerVertical="true"
android:src="#drawable/point_grey" />
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_centerVertical="true"
android:src="#drawable/point_red" />
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerVertical="true"
android:src="#drawable/point_grey" />
</merge>
My activity's layout is activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.ab1209.testcustom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.ab1209.testcustom.view.TreeViewGroup
android:id="#+id/activity_main_custom_tree_node_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
MainActivity class is
**public class MainActivity extends Activity
{
TreeViewGroup treeNodeView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
treeNodeView = (TreeViewGroup) findViewById(R.id.activity_main_custom_tree_node_view);
}
}**
When I run the app I don't see the NodeView added in main View. Am I doing the right thing if not please tell me how can I make it working?
To create a custom ViewGroup, the only method you need to override is
onLayout. The onLayout is triggered after the ViewGroup itself has
finished laying itself out inside its own container ViewGroup and is
now responsible for laying out its children. It should call the layout
method on all of its children to now position and size them (the left
and top parameters will determine the child view’s x and y and the
right and bottom will determine its width (right – left) and height
(top-bottom).
So your TreeViewGroup code will look like :
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) child
.getLayoutParams();
int childLeft = 0;
int childTop = 0;
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(),
childTop + child.getMeasuredHeight());
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
int measuredWidth = 200; // Calculate the height
int measuredHeight = 200; // Calculate the width
setMeasuredDimension(measuredWidth, measuredHeight);
}
Refer this link http://arpitonline.com/2012/07/01/creating-custom-layouts-for-android/

Adding a Custom View as header of ListView

I have a custom view (a class extending View) that I'd like to add as a header of List View. Here's the code snippet:
public class MyActivity extends RoboListActivity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View header = getLayoutInflater().inflate(R.layout.myactivity_apps_header, null);
getListView().addHeaderView(header);
...more code
}
But, I can't see anything. But, when I tried to add a non-custom view, it works. Am I missing something, please guide
Providing Complete Source Code
Custom View
public class SpaceCustomView extends View {
private Paint mPaint;
private Paint mTextPaint;
private final String mMessage = "Foo Bar";
private Rect mBounds;
public StorageSpaceCustomView(Context context) {
super(context);
initInput();
}
public StorageSpaceCustomView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
initInput();
}
public StorageSpaceCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initInput();
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
#Override
public void onDraw(android.graphics.Canvas canvas) {
canvas.drawRect(30, 30, 800, 80, mPaint);
canvas.drawText(mMessage, 30, 60, mTextPaint);
}
private void initInput() {
mBounds = new Rect();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mTextPaint = new Paint();
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextAlign(Paint.Align.LEFT);
mTextPaint.setTextSize(20);
mTextPaint.getTextBounds(mMessage, 0, mMessage.length(), mBounds);
}
}
Header Layout XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.mycompany.app.view.custom.SpaceCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Activity Class
public class AppsActivity extends RoboListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//add header and footer views
View header = getLayoutInflater().inflate(R.layout.activity_apps_header, null);
getListView().addHeaderView(header);
View footer = getLayoutInflater().inflate(R.layout.activity_pps_footer, null);
getListView().addFooterView(footer);
List<AppInfo> applicationList = Mycatalog.getPromotions();
AppListAdapter adapter = new AppListAdapter(this, applicationList);
setListAdapter(adapter);
}
private class AppListAdapter extends ArrayAdapter<AppInfo> {
public AppListAdapter(Activity activity, List<AppInfo> apps) {
super(activity, android.R.layout.simple_list_item_1, apps);
}
#Override
public boolean isEmpty(){
return false;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// if we weren't given a view, inflate one
if (null == convertView) {
convertView = getLayoutInflater()
.inflate(R.layout.activity_uninstall_apps, null);
}
return convertView;
}
}
}
Conclusion: I can see the footer but not the header.
ListView shows headers and footers only when it's Adapter's isEmpty() returns false.
So try setting an adapter that does that...

Categories

Resources