طراحی xml برنامه مانند واتساپ
این کدی هستش که من برای recyclerview نوشتم:
public abstract class MotionScroll extends RecyclerView.OnScrollListener{
private int toolbarOffset=0;
private int toolbarHeight;
private boolean controlsVisible=true;
private int totalScrolledDistance;
private static final int HIDE_OFFSET = 10;
private static final int SHOW_OFFSET = 80;
public MotionScroll(Context context){
toolbarHeight = Utils.getToolbarHeight(context);
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE){
if (totalScrolledDistance < toolbarHeight){
setVisible();
}else{
if (controlsVisible){
if (toolbarOffset > HIDE_OFFSET){
setInvisible();
}else{
setVisible();
}
}else{
if (toolbarHeight - toolbarOffset > SHOW_OFFSET){
setVisible();
}else{
setInvisible();
}
}
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, final int dy) {
super.onScrolled(recyclerView, dx, dy);
clipOffset();
onMoved(toolbarOffset);
if ((toolbarOffset < toolbarHeight && dy >0) || (toolbarOffset > 0 && dy<0)){
toolbarOffset +=dy;
}
totalScrolledDistance +=dy;
}
private void clipOffset(){
if (toolbarOffset > toolbarHeight){
toolbarOffset = toolbarHeight;
}else if (toolbarOffset < 0){
toolbarOffset = 0;
}
}
private void setVisible(){
if (toolbarOffset > 0){
onShow();
toolbarOffset =0;
}
controlsVisible = true;
}
private void setInvisible(){
if (toolbarOffset < toolbarHeight){
onHide();
toolbarOffset = toolbarHeight;
}
controlsVisible = false;
}
public abstract void onMoved(int distance);
public abstract void onShow();
public abstract void onHide();
}
این هم برای scrollview هستش:
public class ParallaxScrollView extends ScrollView {
private OnParallaxScrollChangedListener listener;
public ParallaxScrollView(Context context) {
super(context);
}
public ParallaxScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ParallaxScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public interface OnParallaxScrollChangedListener{
public void onScrollChanged(ParallaxScrollView psv,int l,int t,int oldl,int oldt);
}
public void setOnParallaxScrollView(OnParallaxScrollChangedListener listener){
this.listener = listener;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
listener.onScrollChanged(this,l,t,oldl,oldt);
}
}
یک کلاس کمکی هستش که اندازه تولبار و همچنین تب رو میده که جلوتر بدردمون میخوره:
public class Utils {
public static int getToolbarHeight(Context context) {
final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes(
new int[]{R.attr.actionBarSize});
int toolbarHeight = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle();
return toolbarHeight;
}
public static int getTabsHeight(Context context) {
return (int) context.getResources().getDimension(R.dimen.tabsHeight);
}
}
برای استفاده در recyclerview کد زیر رو در اکتیوتی یا فرگمنتی که recyclerview داره مینویسیم (نمونه من فرگمنت هستش):
final MainActivity mainActivity = (MainActivity) getActivity();
recyclerView.setOnScrollListener(new MotionScroll(getActivity()) {
@Override
public void onMoved(int distance) {
mainActivity.toolbarContainer.setTranslationY(-distance);
}
@Override
public void onShow() {
mainActivity.toolbarContainer.animate().translationY(0).setInterpolator(new AccelerateInterpolator());
}
@Override
public void onHide() {
final int toolbarHeight = Utils.getToolbarHeight(getActivity());
mainActivity.toolbarContainer.animate().translationY(-toolbarHeight).setInterpolator(new DecelerateInterpolator());
}
});
return view;
}
toolbarContainer: با توجه به اینکه اندازه تولبار به نسبت اسکرول RecyclerView تغییر میکنه پس ما باید تغییراتی توی تولبارمون بدیم:
این لایه مربوط به تولبار هستش:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" android:gravity="center">
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="top"
android:background="#00695C"
>
<android.support.v7.widget.Toolbar
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:clipToPadding="false"
android:layout_gravity="center|right"
android:id="@+id/toolbar"
>
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"
android:gravity="right"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="رستوران سبز"
android:id="@+id/txtToolbarTitle" android:textColor="#ffffff"
android:textSize="24dp" android:paddingTop="16dp" android:paddingBottom="16dp"
android:layout_marginRight="4dp"/>
<ImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:id="@+id/imgMore" android:src="@drawable/more"
android:layout_gravity="center" android:layout_marginRight="8dp" android:scaleType="centerInside"
android:background="@drawable/img_more_selector"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</LinearLayout>
</LinearLayout>
دقت کنید که در این مورد باید رنگ پس زمینه تولبار به LinearLayout پدرش داده بشه تا موقع اسکرول کردن فضای خالی بوجود نیاد.
فقط یک چیز دیگه رو هم در نظر داشته باشید که کد بالا تنها روی ورژن 3.2 به بالا اجرا میشود
برای Scrollview هم از کد زیر استفاده کنید:
private int lastTop;
final android.support.v7.widget.Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final ImageView imageView = (ImageView) findViewById(R.id.imageView);
scrollView.setOnParallaxScrollView(new ParallaxScrollView.OnParallaxScrollChangedListener() {
@Override
public void onScrollChanged(ParallaxScrollView psv, int l, int t, int oldl, int oldt) {
toolbar.setY(t);
toolbar.setBackgroundColor(Color.rgb(0, 105, 92));
toolbar.getBackground().setAlpha(getAlpha(psv.getScrollY()));
scrollImage(imageView);
}
});
private int getAlpha(int scrollY){
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int heightPixels = metrics.heightPixels;
int minDist=0;
int maxDist = heightPixels / 3;
if (scrollY > maxDist){
return 255;
}else if (scrollY < minDist){
return 0;
}else{
int alpha;
alpha = (int) ((255.0/maxDist)*scrollY);
return alpha;
}
}
private void scrollImage(ImageView imageView){
Rect rect = new Rect();
imageView.getLocalVisibleRect(rect);
if (lastTop != rect.top){
lastTop = rect.top;
imageView.setY((rect.top / 2.0f));
}
}
کد بالا باعث میشه هنگام اسکرول کردن صفحه رنگ تولبار از محو به رنگی که بهش دادید برسه. همچنین اگر برنامه دیوار رو دیده باشید هنگام اسکرول انگار که عکسی که بالای صفحه است داره جداگانه اسکرول میشه. این مربوط به متد ScrollImage هستش.
پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .
