So I have a bit of a frustrating one for me. What I would like to achieve is essentially a button that has two textviews in the center of it. One with a name and one with a number value to it... Like a counter...
I would like it to look like this:
There is a thin white border around it (which given it's colour isn't exactly visible... sorry).
What I'd like to do is have the value increment and decrement depending on how the button is pressed.
Now I have the following so far:
attrs.xml
<resources>
<declare-styleable name="ButtonCounter">
<attr name="backgroundColor" format="color"/>
<attr name="borderColor" format="color"/>
<attr name="borderSize" format="integer"/>
<attr name="labelNameColor" format="color"/>
<attr name="labelValueColor" format="color"/>
<attr name="labelName" format="string"></attr>
<attr name="labelValue" format="string"></attr>
</declare-styleable>
ButtonCounter.java
public class ButtonCounter extends View {
private int backgroundColor,
borderColor,
borderSize,
labelNameColor,
labelValueColor;
private String labelName,
labelValue;
private Paint paintCircle,
paintStroke;
public ButtonCounter(Context context, AttributeSet attrs) {
super(context);
paintCircle = new Paint();
paintStroke = new Paint();
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.ButtonCounter
,
0,
0
);
try {
backgroundColor = a.getInteger(R.styleable.ButtonCounter_backgroundColor, 0);
borderColor = a.getInteger(R.styleable.ButtonCounter_borderColor, 0);
borderSize = a.getInteger(R.styleable.ButtonCounter_borderSize, 0);
labelNameColor = a.getInteger(R.styleable.ButtonCounter_labelNameColor,0);
labelValueColor = a.getInteger(R.styleable.ButtonCounter_labelValueColor, 0 );
labelName = a.getString(R.styleable.ButtonCounter_labelName);
labelValue = a.getString(R.styleable.ButtonCounter_labelValue);
} finally {
a.recycle();
}
}
#Override
protected void onDraw(Canvas canvas) {
paintCircle.setColor(backgroundColor);
paintCircle.setAntiAlias(true);
paintStroke.setColor(borderColor);
paintStroke.setAntiAlias(true);
int width = this.getMeasuredWidth();
int height = this.getMeasuredHeight();
int diameter = ((height > width) ? height : width);
int radius = diameter / 2;
canvas.drawCircle(diameter / 2, diameter / 2, radius - borderSize, paintCircle);
canvas.drawCircle(diameter / 2, diameter / 2, radius, paintStroke);
}
}
This doesn't do what I want it to already as it becomes way too big.
Any ideas on how I could start attempting this?
Thanks!
Hi If you want to achieve the same without using Java Class then see the below solution:
Create a drawable with any name lets circle_bg_xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#color/black" />
</shape>
Now in your layout use put two TextViews(or any view) inside LinearLayout and set that drawable as Layout background.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="100dp"
android:layout_height="100dp"
android:gravity="center"
android:background="#drawable/circle_bg">
<TextView
android:layout_width="wrap_content"
android:textColor="#color/white"
android:textSize="15sp"
android:layout_height="wrap_content"
android:text="Global"/>
<TextView
android:layout_width="wrap_content"
android:textColor="#color/white"
android:textSize="22sp"
android:layout_height="wrap_content"
android:text="0"/>
</LinearLayout>
Hope it will help you.
Thanks
Related
I have to set progressDrawable for AppCompatSeekBar programmatically but it leads to changing the SeekBar's progressDrawable height after I set it for the second time and further. You can see what I mean below:
What should I do to change this behavior? I already set minHeight and maxHeight to 12dp as it was suggested in another answer.
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatSeekBar
android:id="#+id/seek_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:maxHeight="12dp"
android:minHeight="12dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:progress="50"
android:splitTrack="false"
android:thumb="#drawable/my_thumb" />
<Button
android:id="#+id/change_seek_bar_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:text="Change seek bar" />
</FrameLayout>
my_thumb.xml:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="23dp"
android:height="23dp"
android:viewportWidth="23"
android:viewportHeight="23">
<path
android:fillColor="#B7BDC2"
android:pathData="M11.5,20L11.5,20A9.5,9.5 0,0 1,2 10.5L2,10.5A9.5,9.5 0,0 1,11.5 1L11.5,1A9.5,9.5 0,0 1,21 10.5L21,10.5A9.5,9.5 0,0 1,11.5 20z" />
</vector>
MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.change_seek_bar_button);
SeekBar seekBar = findViewById(R.id.seek_bar);
// sets it the right way
setProgressDrawable(seekBar);
// on button click it sets progressDrawable with wrong height
button.setOnClickListener((view) -> setProgressDrawable(seekBar));
}
private void setProgressDrawable(SeekBar seekBar) {
GradientDrawable progressDrawable = new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,
new int[]{0xFF000000, generateRandomColor()}
);
seekBar.setProgressDrawable(progressDrawable);
}
private int generateRandomColor() {
Random random = new Random();
return Color.argb(255, random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
}
Most probably the problem is in ProgressBar.updateDrawableBounds(int w, int h). When it calls mProgressDrawable.setBounds(0, 0, right, bottom), it doesn't really take into account that progressDrawable might not be equal to the height of the whole View. But initially this function is called when width and height are 0's and I guess that's why it works for the first time.
The problem is kind of clear, so the most obvious solution is to change bounds after setting new progressDrawable:
button.setOnClickListener((view) -> {
setProgressDrawable(seekBar);
// converting 12 dp to pixels
int desiredHeight = (int) (12 * Resources.getSystem().getDisplayMetrics().density);
Rect bounds = seekBar.getProgressDrawable().copyBounds();
int actualTop = (int) Math.round((bounds.bottom - bounds.top) / 2.0 - desiredHeight / 2.0);
seekBar.getProgressDrawable().setBounds(bounds.left, actualTop, bounds.right, actualTop + desiredHeight);
});
And it actually solves the problem.
I'm creating an animation in View. After the user click button that become as circle. I'm using Scale animation to archive this. but my view layout radius change after click the button. how can i keep the same radius during the animation or are they anyway to achieve this without libraries ?
view xml
<View
android:id="#+id/containerView"
android:layout_width="363dp"
android:layout_height="45dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="188dp"
android:background="#drawable/login_boader_round"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.333"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/login_screen_credential_view_holder" />
login_boader_round xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners
android:pivotX="100%"
android:pivotY="100%"
android:radius="45dp"
/>
<padding
android:bottom="0dp"
android:left="0dp"
android:right="0dp"
android:top="0dp" />
<solid android:color="#677FFF" />
<!--<stroke-->
<!-- android:width="3dp"-->
<!-- android:color="#50A4D1" />-->
</shape>
After the button click event
public void scaleViewAnimation(View view) {
ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 0, 1f, 1f, Animation.RESTART, 0.5f, Animation.RESTART, 0.5f);
scaleAnimation.setDuration(ANIMATION_FADE_DURATION);
scaleAnimation.setFillAfter(true);
view.startAnimation(scaleAnimation);
}
ScaleAnimation class does not have that property. so i used ValueAnimator class to active this. ANIMATION_TIME is an integer. you want to give
ValueAnimator anim = ValueAnimator.ofInt(view.getMeasuredWidth(), view.getMeasuredHeight());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = val;
view.requestLayout();
}
});
anim.setDuration(ANIMATION_TIME);
anim.start();
I have been working on a custom "Button" and it works just as I want it to so far. However, I am trying to add text to the button instead of a drawable (which is what I was doing before).
Currently I have used a declare-styleable in my attrs.xml file which looks like the following:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Custom attributes for the button -->
<declare-styleable name="StyledButton">
<attr name="cornerRadius" format="dimension" />
<attr name="borderWidth" format="dimension" />
<attr name="startColor" format="color" />
<attr name="centerColor" format="color" />
<attr name="endColor" format="color" />
</declare-styleable>
</resources>
Alongside this, I have the accompanying class StyledButton.java :
package com.example.test;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.graphics.Path;
import android.graphics.Paint;
import android.graphics.LinearGradient;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageButton;
public class StyledButton extends AppCompatImageButton {
private float cornerRadius = 0f;
private float borderWidth = 0f;
private int startColor = 0;
private int centerColor = 0;
private int endColor = 0;
private Path path = new Path();
private Paint borderPaint = new Paint();
{
borderPaint.setStyle(Paint.Style.FILL);
}
public StyledButton(Context context, #Nullable AttributeSet attrs) {
super(context, attrs, 0);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StyledButton);
try {
cornerRadius = a.getDimension(R.styleable.StyledButton_cornerRadius, 10f);
borderWidth = a.getDimension(R.styleable.StyledButton_borderWidth, 10f);
startColor = a.getColor(R.styleable.StyledButton_startColor, getResources().getColor(R.color.colorPrimaryDark, context.getTheme()));
centerColor = a.getColor(R.styleable.StyledButton_centerColor, getResources().getColor(R.color.colorAccent, context.getTheme()));
endColor = a.getColor(R.styleable.StyledButton_endColor, Color.WHITE);
}
finally {
a.recycle();
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
borderPaint.setShader(new LinearGradient(0f, 0f, 0f, (float) getHeight(), new int[] {startColor, centerColor, endColor}, null, Shader.TileMode.CLAMP));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path.rewind();
path.addRoundRect(borderWidth, borderWidth, ((float) getWidth()) - borderWidth, ((float) getHeight()) - borderWidth, cornerRadius - borderWidth / 2, cornerRadius - borderWidth / 2, Path.Direction.CCW);
canvas.clipOutPath(path);
path.rewind();
path.addRoundRect(0f, 0f, ((float) getWidth()), ((float) getHeight()), cornerRadius, cornerRadius, Path.Direction.CCW);
canvas.drawPath(path, borderPaint);
}
}
I am trying to use these in a custom dialog to get user input with the following code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:elevation="5dp">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="20dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/background_gradient"
android:padding="10dp">
<TextView
android:layout_width="300dp"
android:layout_height="wrap_content"
android:scaleType="center"
android:text="#string/app_name"
android:textAlignment="center"
android:fontFamily="#font/lato_bold"
android:textSize="36sp"
android:padding="10dp"
android:textColor="#android:color/white" />
<EditText
android:id="#+id/player_name_dialog_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:hint="#string/player_name_hint"
android:textAlignment="center"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="40dp"
android:orientation="horizontal"
android:layout_gravity="center"
android:layout_marginTop="10dp">
<com.example.test.StyledButton
android:id="#+id/player_name_dialog_confirm_button"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_width="120dp"
android:scaleType="center"
android:layout_gravity="center"
app:startColor="#color/colorPrimaryDark"
app:centerColor="#color/colorPrimary"
app:endColor="#color/colorAccent"
app:borderWidth="2dp"
app:cornerRadius="20dp"
android:text="#string/cancel"
android:textColor="#android:color/white"
android:textSize="20sp"
android:fontFamily="#font/lato"
android:layout_marginHorizontal="10dp"
android:onClick="deletePlayerButtonClick"/>
<com.example.test.StyledButton
android:id="#+id/add_players_activity_delete_button"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_width="120dp"
android:scaleType="center"
android:layout_gravity="center"
app:startColor="#color/colorPrimaryDark"
app:centerColor="#color/colorPrimary"
app:endColor="#color/colorAccent"
app:borderWidth="2dp"
app:cornerRadius="20dp"
android:layout_marginHorizontal="10dp"
android:onClick="deletePlayerButtonClick"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
I have tried adding the android:text in the attrs.xml file but this doesn't show up and I don't understand why this may be.
Thanks in advance !
The text will not show as the custom view extends AppCompatImageButton. AppCompatImageButton only displays an image.
public class StyledButton extends AppCompatImageButton {
If you require a button that shows text consider having two custom views, one for image and the other for text.
StyledImageButton:
public class StyledImageButton extends AppCompatImageButton {
StyledButton
public class StyledButton extends AppCompatButton {
The rest of the code can remain the same.
NOTE: Android will not let you create duplicate attributes in attrs.xml. Create global attributes and reuse them. Like so:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="cornerRadius" format="dimension" />
<attr name="borderWidth" format="dimension" />
<attr name="startColor" format="color" />
<attr name="centerColor" format="color" />
<attr name="endColor" format="color" />
<declare-styleable name="StyledButton">
<attr name="cornerRadius" />
<attr name="borderWidth" />
<attr name="startColor" />
<attr name="centerColor" />
<attr name="endColor" />
</declare-styleable>
<declare-styleable name="StyledImageButton">
<attr name="cornerRadius" />
<attr name="borderWidth" />
<attr name="startColor" />
<attr name="centerColor" />
<attr name="endColor" />
</declare-styleable>
</resources>
I want to create an EditText like the Image below.
This is what I want to achieve
This is my code (in the xml file of the layout):
<EditText
android:id="#+id/newThoughtThoughtText"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="#drawable/lines"
android:gravity="top"
android:hint="#string/thought_first_text"
android:inputType="textMultiLine"
android:maxLines="15"
android:textColor="#color/color_gray" />
I have created a custom drawable layout file. But this only enables me to have one line at the end, and I need several lines inside the EditText.
How can I do this?
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<stroke
android:width="1dp"
android:color="#color/color_gray" />
</shape>
</item>
</layer-list>
Thanks in advance!
To achieve this you have to make changes in your drawable class which you have created.
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="-2dp"
android:insetRight="-2dp"
android:insetTop="-2dp">
<shape android:shape="rectangle" >
<stroke
android:width="1dp"
android:color="#000000" />
<solid android:color="#color/md_grey_200" />
</shape>
</inset>
This will give you border bottom and you can change color according to your requirement.
If you don't want to give border to the each EditText you can add one View after each EditText like this.
<View
style="#style/MenuDivider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginEnd="5dp"
android:layout_marginStart="5dp"
android:layout_marginTop="15dp"
android:background="#color/black"/>
You can change the view height according and background to you.
Hope this will help you.
I managed to solve the problem and to design the editText as wished.
This topic helped me:
Android - How to make all lines in an edittext underlined?
I created my own custom EditText:
package com.example.appsiety.utils;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import com.example.appsiety.R;
public class EditTextThought extends android.support.v7.widget.AppCompatEditText {
private Paint mPaint = new Paint();
private Context context;
public EditTextThought(Context context) {
super(context);
this.context = context;
initPaint();
}
public EditTextThought(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
initPaint();
}
public EditTextThought(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
initPaint();
}
private void initPaint() {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(ContextCompat.getColor(context, R.color.color_gray));
}
#Override protected void onDraw(Canvas canvas) {
int left = getLeft();
int right = getRight();
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
int height = getHeight();
int lineHeight = getLineHeight();
int count = (height-paddingTop-paddingBottom) / lineHeight;
for (int i = 0; i < count*2; i++) {
int baseline = lineHeight * (i+1) + paddingTop;
canvas.drawLine(left+paddingLeft, baseline, right-paddingRight, baseline, mPaint);
}
super.onDraw(canvas);
}
}
and then in my layout file i used it:
<view
class="com.example.appsiety.utils.EditTextThought"
android:id="#+id/newThoughtSituationText"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:scrollbars="vertical"
android:fadingEdge="vertical"
android:gravity="top"
android:textSize="18sp"
android:fontFamily="#font/opensans_light"
android:textColorHint="#color/color_gray"
android:textColor="#color/color_gray"
android:hint="#string/situation_first_text"
android:background="#android:color/transparent"
android:inputType="textMultiLine|textVisiblePassword"
/>
When I scroll within my Android scrollview, it scrolls down as it should.
But I'd like the image within the imageview to anchor to the centre. So you always see the face of the person in the image as you scrolling up.
So far I have not been able to accomplish this
A similar effect is created in the image below:
Stockguy image:
My code so far (which so far doesn't accomplish this):
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fillViewport="true"
android:scrollbars="none"
android:background="#FAFAFA"
android:id="#+id/cScrollview"
>
<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="1100dp"
tools:context=".MainActivity"
android:id="#+id/CRLayout">
<ImageView
android:layout_gravity="center"
android:adjustViewBounds="true"
android:layout_width="601dp"
android:layout_height="250dp"
android:paddingTop="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:scaleType="centerCrop"
android:id="#+id/contactPic"
android:src="#drawable/stockguy"/>
....
</RelativeLayout>
</ScrollView>
To achieve parallax effect like on image you posted try following code. It is a very simple way.
Layout:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/rlWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/ivContactPhoto"
android:layout_width="match_parent"
android:layout_height="#dimen/contact_photo_height"
android:scaleType="centerCrop"
android:src="#drawable/stockguy" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="#dimen/contact_photo_height"
android:layout_marginTop="250dp">
<!-- Other Views -->
</LinearLayout>
</RelativeLayout>
</ScrollView>
LinearLayout's top margin is equal to the ImageViews's height.
Listening scroll position of the ScrollView and changing position of ImageView:
#Override
protected void onCreate(Bundle savedInstanceState) {
<...>
mScrollView = (ScrollView) findViewById(R.id.scrollView);
mPhotoIV = (ImageView) findViewById(R.id.ivContactPhoto);
mWrapperRL = (RelativeLayout) findViewById(R.id.rlWrapper);
mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ScrollPositionObserver());
<...>
}
private class ScrollPositionObserver implements ViewTreeObserver.OnScrollChangedListener {
private int mImageViewHeight;
public ScrollPositionObserver() {
mImageViewHeight = getResources().getDimensionPixelSize(R.dimen.contact_photo_height);
}
#Override
public void onScrollChanged() {
int scrollY = Math.min(Math.max(mScrollView.getScrollY(), 0), mImageViewHeight);
// changing position of ImageView
mPhotoIV.setTranslationY(scrollY / 2);
// alpha you can set to ActionBar background
float alpha = scrollY / (float) mImageViewHeight;
}
}
Hope it will help.
I'd take a different approach with that.
Try building your layout based on the following snippet:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:background="#00FF00"
android:scaleType="centerCrop"
android:layout_height="200dp"/>
<FrameLayout
android:id="#+id/content"
android:layout_below="#+id/image"
android:background="#FF0000"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
Using the GestureDetector.SimpleOnGestureListeneryou can detect when the user scrolls on the content layout and update the image size and alpha accordingly to get the effect you describe.
I would implement this using a scroll callback on the ScrollView, this doesn't exist by default but is easy to create yourself by extending ScrollView:
public class UpdatingScrollView extends ScrollView {
private OnScrollChangedListener mScrollChangedListener;
public interface OnScrollChangedListener {
public void onScrollChanged(int x, int y, int oldx, int oldy);
}
public UpdatingScrollView(Context context) {
super(context);
}
public UpdatingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public UpdatingScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setOnScrollChangedListener(OnScrollChangedListener listener) {
mScrollChangedListener = listener;
}
#Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (mScrollChangedListener != null) mScrollChangedListener.onScrollChanged(x, y, oldx, oldy);
}
}
So replace ScrollView in your layout with com.your.package.UpdatingScrollView.
In your Fragment/Activity where the UpdatingScrollView is defined you set the scroll listener and update the bottom margin of the image based on the scroll offset. For every 2 pixels the ScrollView has scrolled you'll want to update the bottom margin by -1 pixel which will make the image move up the screen at half the rate of the rest of the content.
So something like this:
scrollView.setOnScrollChangedListener(new OnScrollChangedListener() {
#Override
public void onScrollChanged(int x, int y, int oldx, int oldy) {
// I think y will be negative when scrolled
if(y >= -image.getHeight()) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) image.getLayoutParams();
lp.setMargins(0, 0, 0, y / 2);
image.setLayoutParams(lp);
}
}
});