i am currently rewriting our app from ios to android and I couln't get a proper effect to work. So in iOS we used the this library to achieve the fixed header over the content scrollview with parallax effect. I quickly modified the example and export it as a gif so it's more clear what we're trying to achieve:
So first of all I tried something with CollapsingToolbarLayout where I came across this snippet. So basically the snippet adds a AppBarLayout.Behavior what achieves the zoom effect. Overhaul it does not feel smooth.
Next I found PullZoomView which seems popular in android. The zoom and the scroll behaviour feels great. The only problem is that the header is not fixed and gets overscrolled by the listview like this:
So I dig into the code and tried to modified it for my propose but it seems hacky and complicated.
So it seems like from what I saw in all libraries that this overscroll over the header behaviour is more in common. Does someone has any advice how can I achieve the behaviour like I want before I write my own solution? Is there any library maybe which I don't found?
Doesn't directly answer your question but I made a library that has a component which expands on click/touch. I think you might be able to use the code to create your own scrollbar header thing.
https://github.com/NadavTasher/ToolLibs/blob/master/lightool/src/main/java/nadav/tasher/lightool/graphics/views/ExpandingView.java
e.g. Make the fixed view your header, and the expanding view your scrollview
I wrote a solution by my own right after I submit this question. I really liked the concept in the library from iOS that you can have individual UIViewController for the header and for the content part so in Android it seems that Fragments are the way to go here. I want to share my code if anyone want to have the same effect:
Add the following dependencies to yur build.gradle:
implementation 'me.everything:overscroll-decor-android:1.0.4'
implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0'
My class (sorry it's a bit messy):
public abstract class ParallaxHeaderActivity extends AppCompatActivity implements ObservableScrollViewCallbacks {
private ObservableScrollView scrollView;
private LinearLayout headerView;
private FrameLayout contentView;
private int headerHeight = 0;
private int minimumHeaderHeight = 0;
protected void setContentView(int layout, Fragment header, Fragment content){
super.setContentView(layout);
ViewGroup rootView = (ViewGroup) ((ViewGroup) this
.findViewById(android.R.id.content)).getChildAt(0);
headerHeight = (int)convertDpToPixel(260, this);
minimumHeaderHeight = (int)convertDpToPixel(160, this);
int contentViewId = View.generateViewId();
contentView = new FrameLayout(this);
contentView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
contentView.setPadding(0, headerHeight, 0, 0);
contentView.setId(contentViewId);
scrollView = new ObservableScrollView(this);
scrollView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
scrollView.setScrollViewCallbacks(this);
scrollView.setFillViewport(true);
scrollView.addView(contentView);
scrollView.setScrollViewCallbacks(this);
IOverScrollDecor decor = new VerticalOverScrollBounceEffectDecorator(new ScrollViewOverScrollDecorAdapter(scrollView));
decor.setOverScrollUpdateListener(new IOverScrollUpdateListener() {
#Override
public void onOverScrollUpdate(IOverScrollDecor decor, int state, float offset) {
if (offset > 0) {
// 'view' is currently being over-scrolled from the top.
update((int)-offset);
}
}
});
rootView.addView(scrollView);
addFragment(contentViewId, content);
int headerViewId = View.generateViewId();
headerView = new LinearLayout(this);
headerView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, headerHeight));
headerView.setId(headerViewId);
rootView.addView(headerView);
addFragment(headerViewId, header);
}
#Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
update(scrollY);
}
#Override
public void onDownMotionEvent() {
}
#Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
}
private void addFragment(int id, Fragment fragment){
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(id, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
private void update(final int scrollY) {
headerView.getLayoutParams().height = Math.max(headerHeight - scrollY, minimumHeaderHeight);
headerView.requestLayout();
}
public static float convertDpToPixel(float dp, Context context){
return dp * ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
}
In your Activity you can call it like:
setContentView(R.layout.activity_main, new HeaderFragment(), new ContentFragment());
fragment_content.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="wrap_content"
tools:context=".ContentFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:text="#string/lipsum"/>
</FrameLayout>
fragment_header.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
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">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
android:src="#drawable/example"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:text="Test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:minHeight="?attr/actionBarSize"
android:textColor="#android:color/white"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Related
Before using FragmentStateAdapter. I was using FragmentPagerAdapter then everything was fine but when I migrated from FragmentPagerAdapter to FragmentStateAdapter to reduce memory usage. The issue that I'm facing is that when RecyclerView is at the top position then clicking on any item in the list is not working. If I scroll the RecyclerView a bit down then onClick works fine. This problem was not happening with SwipeRefreshLayout. When I remove SwipeRefreshLayout from parent of RecyclerView. It working fine. How can I use it with SwipeRefreshLayout?
I'm using children Fragments inside a parent Fragment like this
This is the code of Parent Fragment.
public class DailyFragment extends Fragment {
private FragmentDailyBinding binding;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentDailyBinding.inflate(inflater, container, false);
MyChildFragmentAdapter childFragmentAdapter = new MyChildFragmentAdapter(this.getChildFragmentManager(), this.getLifecycle()); // I'm showing these fragment in Parent fragment. So that I'm using getChildFragmentManager()
childFragmentAdapter.addFragment(new FirstFragment(),"first");
childFragmentAdapter.addFragment(new SecondFragment(),"second");
childFragmentAdapter.addFragment(new ThirdFragment(),"third");
childFragmentAdapter.addFragment(new FourthFragment(),"fourth");
childFragmentAdapter.addFragment(new FifthFragment(),"fifth");
binding.dailyViewPager.setAdapter(childFragmentAdapter);
new TabLayoutMediator(binding.dailyTabLayout, binding.dailyViewPager, (tab, position) -> tab.setText(childFragmentAdapter.fragmentsArrayListTitle.get(position))).attach();
binding.dailyViewPager.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
return binding.getRoot();
}
// FragmentStateAdapter
public static class MyChildFragmentAdapter extends FragmentStateAdapter {
private final ArrayList<Fragment> fragmentsArrayList = new ArrayList<>();
private final ArrayList<String> fragmentsArrayListTitle = new ArrayList<>();
public MyChildFragmentAdapter(#NonNull FragmentManager fragmentManager, #NonNull Lifecycle lifecycle) {
super(fragmentManager, lifecycle);
}
public void addFragment(Fragment fragment, String title) {
fragmentsArrayList.add(fragment);
fragmentsArrayListTitle.add(title);
}
#NonNull
#Override
public Fragment createFragment(int position) {
return fragmentsArrayList.get(position);
}
#Override
public int getItemCount() {
return fragmentsArrayList.size();
}
}
}
and This this XML of FirstFragment()
<?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:orientation="vertical"
android:layout_height="match_parent"
tools:context=".ChieldFragment.dailyChield.MahadevFragment">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="#+id/mahadevSwipe"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/mahadevRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>
My question is similar to this question
ViewPager2 conflicting with SwipeRefreshLayout
I checked these answers but not solved my problem.
I had same problem not so long ago. I fixed mine by adding NestedScrollView as SwipeRefreshLayout child, and then simply put your recycler layout as NestedScrollView's child. See example below :
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="#+id/mahadevSwipe"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
// I didn't put mandatory constraints, but you'll have to
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/mahadevRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
Alternatively, you could also keep your code like it is, and add custom scrolling behavior with scroll listener.
Tell me if my first guess don't work, i'll give you example of custom scroll handling.
Try adding app:layout_behavior="#string/appbar_scrolling_view_behavior" to all views under coordinator layout.
I want to have a layout constantly on top of everything and visible all the time, however, once I swipe to the next element in the ViewPager, the FrameLayout is getting behind the ViewPager.
<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:gravity="center_vertical"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/videosViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="0dp">
</androidx.viewpager2.widget.ViewPager2>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<FrameLayout
android:id="#+id/preview_display_layout"
android:layout_width="200dp"
android:layout_height="200dp"
android:visibility="visible"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteX="216dp"
tools:layout_editor_absoluteY="0dp">
</FrameLayout>
</RelativeLayout>
</RelativeLayout>
I tried to place a button instead of and on top of the FrameLayout and, guess what, the button remains on top of everything without going behind the ViewPager after each sroll.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/videosViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="0dp">
</androidx.viewpager2.widget.ViewPager2>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="197dp"
android:layout_height="286dp">
</Button>
<FrameLayout
android:id="#+id/preview_display_layout"
android:layout_width="197dp"
android:layout_height="286dp"
android:visibility="visible"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteX="216dp"
tools:layout_editor_absoluteY="0dp">
</FrameLayout>
</RelativeLayout>
</FrameLayout>
Here is my code in MainActivity
private ViewPager2 videosViewPager;
private SurfaceView previewDisplayView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentViewLayoutResId());
previewDisplayView = new SurfaceView(this);
setupPreviewDisplayView();
videosViewPager = findViewById(R.id.videosViewPager);
List<VideoItem> videoItems = new ArrayList<>();
VideoItem life = new VideoItem();
String path = "android.resource://"+getPackageName()+"/"+ R.raw.video;
life.videoURL = Uri.parse(path);
videoItems.add(life);
VideoItem rest = new VideoItem();
String path2 = "android.resource://"+getPackageName()+"/"+ R.raw.video1;
rest.videoURL = Uri.parse(path);
videoItems.add(rest);
videosViewPager.setAdapter(new VideoAdapter(videoItems));
}
private void setupPreviewDisplayView() {
previewDisplayView.setVisibility(View.GONE);
ViewGroup viewGroup = findViewById(R.id.preview_display_layout);
viewGroup.addView(previewDisplayView);
previewDisplayView
.getHolder()
.addCallback(
new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
processor.getVideoSurfaceOutput().setSurface(holder.getSurface());
Log.d("Surface","Surface Created");
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
onPreviewDisplaySurfaceChanged(holder, format, width, height);
Log.d("Surface","Surface Changed");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
processor.getVideoSurfaceOutput().setSurface(null);
Log.d("Surface","Surface destroy");
}
});
}
I guess my issue is in adding SurfaceView(previewDisplayView)in ViewGroup.
What can I do to make the previewDisplayView get always on top of everything? By the way, I tried bringToFront(), but after a swipe the previewDisplayLayout is automatically going behind the ViewPager.
Thank you in advance
Have you tried android:elevation property ? I think it is what you're looking for,
Hope will help
The basic view hierarchy is this:
secondActivity
linearLayout(LinearLayout)
constLayout(ConstraintLayout)
textbox(TextView)
image(ImageView)
image2
image3
...
The textbox TextView has visibility GONE, and goal is to make it VISIBLE on clicking other visible siblings, change some colors and text, and when clicked again it must be invisible again and reverse all changes.
Cant understand whatever it is that am missing. I have checked many older projects in which I did the same thing and cant find any visible differences as to why this code is not working now.
secondActivity.java
public class secondActivity extends Activity {
public boolean isTextBoxHidden;
public ConstraintLayout constLayout;
public TextView textbox;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
constLayout = findViewById(R.id.constLayout);
textbox = findViewById(R.id.textbox);
isTextBoxHidden = false;
// SETTING UP LISTENER
View.OnClickListener clickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!isTextBoxHidden) {
constLayout.setBackgroundColor(Color.BLACK); //setting color on previously
v.setBackgroundColor(Color.BLACK); //setting color on visible view
textbox.setText("whatever");
textbox.setVisibility(View.VISIBLE); //was gone
isTextBoxHidden = true;
}
else {
textbox.setVisibility(View.GONE); //hide again
constLayout.setBackgroundColor(Color.WHITE);
v.setBackgroundColor(Color.WHITE);
isTextBoxHidden = false;
}
}
};
// INSERTING LISTENERS into all children
for(int i=0; i<constLayout.getChildCount(); i++) {
constLayout.getChildAt(i).setOnClickListener(clickListener);
}
}
}
activity_second.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:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".secondActivity">
<android.support.constraint.ConstraintLayout
android:id="#+id/constLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white">
<TextView
android:id="#+id/textbox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="example"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageButton
android:id="#+id/image"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:src="#drawable/example"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<!--few more clones of the first imageButton-->
</android.support.constraint.ConstraintLayout>
</LinearLayout>
I can't see where you're setting textbox reference, so maybe that's a clue.
Edit:
Did compiled that example you have provided and everything works correctly, but i assume that [...] gone again for good meant you probably want this to be one shot action so instead of boolean just use Boolean and compare it to null.
Edit:
On the second thought you can just remove isTextBoxHidden = false; in else branch
I`ve been looking for a way to enable the MPAndroidChart to only display the value(label) of data point when clicked. But It seems that I could not find it online even in the documentation.
I used the line chart and what I want is to only display the label of the certain point when clicked.
1- Enable touch in the chart
chart.setTouchEnabled(true);
2 - Create MarkerView
public class CustomMarkerView extends MarkerView {
private TextView tvContent;
public CustomMarkerView (Context context, int layoutResource) {
super(context, layoutResource);
// this markerview only displays a textview
tvContent = (TextView) findViewById(R.id.tvContent);
}
// callbacks everytime the MarkerView is redrawn, can be used to update the
// content (user-interface)
#Override
public void refreshContent(Entry e, Highlight highlight) {
tvContent.setText("" + e.getVal()); // set the entry-value as the display text
}
#Override
public int getXOffset() {
// this will center the marker-view horizontally
return -(getWidth() / 2);
}
#Override
public int getYOffset() {
// this will cause the marker-view to be above the selected value
return -getHeight();
}
}
3 - Create the tvContent view
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#drawable/markerImage" >
<TextView
android:id="#+id/tvContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="7dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:text=""
android:textSize="12dp"
android:textColor="#android:color/white"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
4. Set the view Marker in the chart
CustomMarkerView mv = new CustomMarkerView (Context, R.layout.custom_marker_view_layout);
chart.setMarkerView(mv);
https://github.com/PhilJay/MPAndroidChart/wiki/MarkerView
Use IMarker Interface (MarkerView has been deprecated since release 3.0.0)
1. Create a new class that implements the IMarker interface
public class YourMarkerView extends MarkerView {
private TextView tvContent;
public MyMarkerView(Context context, int layoutResource) {
super(context, layoutResource);
// find your layout components
tvContent = (TextView) findViewById(R.id.tvContent);
}
// callbacks everytime the MarkerView is redrawn, can be used to update the
// content (user-interface)
#Override
public void refreshContent(Entry e, Highlight highlight) {
tvContent.setText("" + e.getY());
// this will perform necessary layouting
super.refreshContent(e, highlight);
}
private MPPointF mOffset;
#Override
public MPPointF getOffset() {
if(mOffset == null) {
// center the marker horizontally and vertically
mOffset = new MPPointF(-(getWidth() / 2), -getHeight());
}
return mOffset;
}}
2. set your marker to the chart
IMarker marker = new YourMarkerView();
chart.setMarker(marker);
Reference: https://github.com/PhilJay/MPAndroidChart/wiki/IMarker-Interface
Example in Kotlin for future you:
Define marker layout i.e. gold_marker_layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="#+id/tvContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="6828.1465"
android:textSize="12sp"
android:textColor="#android:color/white"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Quick note: I set the initial text to 6828.1465 because that's my max-width text - watch out here.
If you don't need getXOffset and getYOffset you can assign marker like that:
lineChart.marker = object : MarkerView(context, R.layout.gold_marker_layout) {
override fun refreshContent(e: Entry, highlight: Highlight) {
(findViewById<View>(R.id.tvContent) as TextView).text = "${e.y}"
}
}
That's it, you should be good to go
I've wrote a small application, which shows several android cards. But I'd like to be able to set a colour and title to the top of the card like in the image below, so far I haven't found any information online how to do this. So some help would be fantastic :-)
(My code so far does not accomplish the above, so far my code just produces regular all white cardviews)
My code so far is below:
CardAdapter.java
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
public List<TTItem> posts = new ArrayList<>();
public void addItems(List<TTItem> items) {
posts.addAll(items);
notifyDataSetChanged();
}
public void clear() {
posts.clear();
notifyDataSetChanged();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
View view = View.inflate(context, R.layout.item_cardview, null);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.mTextView.setText(posts.get(position).title);
Picasso.with(holder.mImageView.getContext()).load(posts.get(position).images[0]).into(holder.mImageView);
}
#Override
public int getItemCount() {
return posts.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
public TextView mTextView;
public ImageView mImageView;
public ViewHolder(View view) {
super(view);
mTextView = (TextView) view.findViewById(R.id.textview);
mImageView = (ImageView) view.findViewById(R.id.imageView);
}
}
}
MainActivity.java
public class MainActivity extends ActionBarActivity implements SwipeRefreshLayout.OnRefreshListener {
#InjectView(R.id.mainView)
RecyclerView mRecyclerView;
#InjectView(R.id.refreshContainer)
SwipeRefreshLayout refreshLayout;
private LinearLayoutManager mLayoutManager;
private CardAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
mRecyclerView.setHasFixedSize(true);
refreshLayout.setOnRefreshListener(this);
TypedValue tv = new TypedValue();
int actionBarHeight = 0;
if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}
refreshLayout.setProgressViewEndTarget(true, actionBarHeight);
mAdapter = new CardAdapter();
mRecyclerView.setAdapter(mAdapter);
// use a linear layout manager
mLayoutManager = new GridLayoutManager(this, 1);
mRecyclerView.setLayoutManager(mLayoutManager);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return super.onOptionsItemSelected(item);
}
#Override
public void onRefresh() {
mAdapter.clear();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
refreshLayout.setRefreshing(false);
}
}, 2500);
}
}
Activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/refreshContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/mainView"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
item_cardview.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="200dp"
android:layout_height="200dp"
android:padding="10dp"
card_view:cardCornerRadius="2dp"
card_view:contentPadding= "5dp"
card_view:cardUseCompatPadding="true"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="150dp"
android:scaleType="centerCrop"/>
<TextView
android:id="#+id/textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:layout_gravity="center"/>
</LinearLayout>
</android.support.v7.widget.CardView>
The only change I've made from yours is, card_view:cardCornerRadius="8dp"> and removed the imageview(as no longer needed)
Screenshot of flashcard not filling to half of card:
I believe this is (almost) exact layout of what you want. It is pretty self-explanatory but feel free to ask if something's not clear.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:cardElevation="8dp"
card_view:cardCornerRadius="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout <!-- This is the specific part you asked to color -->
android:id="#+id/heading_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/teal_500"
android:padding="36dp"
android:orientation="vertical">
<TextView
android:id="#+id/tv_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="22 mins to Ancona"
android:textColor="#color/white"
android:textStyle="bold"
android:textSize="36sp" />
<TextView
android:id="#+id/tv_subheading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_below="#+id/tv_heading"
android:text="Light traffic on ss16"
android:textColor="#color/teal_200"
android:textSize="24sp" />
</LinearLayout>
<ImageView
android:id="#+id/iv_map"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="Assigned delivery boy"
android:scaleType="fitXY"
android:src="#drawable/bg_map" />
<TextView
android:id="#+id/tv_footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_below="#+id/tv_heading"
android:text="It is just an example!"
android:textColor="#color/grey_500"
android:textStyle="bold"
android:textSize="24sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
I have replaced your mapFragment (presumably) with imageView to reduce complications.
Update: As the question now addresses the infamous "round corner" problem, this is actually by design. Yes, it is a big flaw. But the solution (as given in docs Here) would be to use card_view:cardPreventCornerOverlap="false" attribute (which I don't think does anything good because it just makes card square again).
See these questions for a good reference to this problem:
Appcompat CardView and Picasso no rounded Corners
Make ImageView fit width of CardView
From my understanding, you can change the colour of a CardView in it's entirety but not parts of it. I'm not sure how that would even work.
What you can do, is nest a TextView with the title within the CardView, then colour the background of the TextView to the colour you would like. Use appropriate margins/padding for a uniform look. Add a background to your TextView and see what you get.
Your TextView is already using the match_parent parameter on your android:layout_width="" so you would only need to add the background like so:
<TextView
android:id="#+id/textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:layout_gravity="center"
android:background="#FF4444"/>
To change the entire CardView colour like I mentioned at the beginning you can do it the same way or programmatically like so:
cardView.setCardBackgroundColor(COLOURHERE);