improved refresh indicator

This commit is contained in:
Mariotaku Lee 2015-03-12 17:43:28 +08:00
parent 6ffd5d6275
commit 40a2e9a5b7
7 changed files with 142 additions and 109 deletions

View File

@ -23,6 +23,7 @@ import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import org.mariotaku.twidere.Constants;

View File

@ -955,21 +955,6 @@ public class HomeActivity extends BaseSupportActivity implements OnClickListener
}
public void moveControlBarBy(float delta) {
final int min = -getControlBarHeight(), max = 0;
mTabsContainer.setTranslationY(MathUtils.clamp(mTabsContainer.getTranslationY() + delta, max, min));
final ViewGroup.LayoutParams ablp = mActionsButton.getLayoutParams();
final int totalHeight;
if (ablp instanceof MarginLayoutParams) {
final MarginLayoutParams mlp = (MarginLayoutParams) ablp;
totalHeight = mActionsButton.getHeight() + mlp.topMargin + mlp.bottomMargin;
} else {
totalHeight = mActionsButton.getHeight();
}
mActionsButton.setTranslationY(MathUtils.clamp(mActionsButton.getTranslationY() - delta, totalHeight, 0));
notifyControlBarOffsetChanged();
}
private static class ControlBarOffsetProperty extends Property<IControlBarActivity, Float> {
public static final ControlBarOffsetProperty SINGLETON = new ControlBarOffsetProperty();

View File

@ -29,6 +29,7 @@ import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBar.OnMenuVisibilityListener;
import android.support.v7.widget.ShareActionProvider;
import android.view.LayoutInflater;
import android.view.Menu;
@ -146,6 +147,8 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement
} else {
mActionBar.hide();
}
findViewById(R.id.media_status).setVisibility(visible ? View.VISIBLE : View.GONE);
}
private void toggleBar() {

View File

@ -1,5 +1,6 @@
package org.mariotaku.twidere.fragment.support;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -25,6 +26,8 @@ import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IControlBarActivity;
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarOffsetListener;
import org.mariotaku.twidere.activity.support.BaseSupportActivity;
import org.mariotaku.twidere.adapter.AbsStatusesAdapter;
import org.mariotaku.twidere.adapter.AbsStatusesAdapter.StatusAdapterListener;
@ -51,8 +54,8 @@ import static org.mariotaku.twidere.util.Utils.setMenuForStatus;
* Created by mariotaku on 14/11/5.
*/
public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment implements LoaderCallbacks<Data>,
OnRefreshListener, DrawerCallback, RefreshScrollTopInterface, StatusAdapterListener {
OnRefreshListener, DrawerCallback, RefreshScrollTopInterface, StatusAdapterListener,
ControlBarOffsetListener {
private final Object mStatusesBusCallback;
private AbsStatusesAdapter<Data> mAdapter;
@ -63,7 +66,7 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView;
private SimpleDrawerCallback mDrawerCallback;
private int mTouchSlop;
private OnScrollListener mOnScrollListener = new OnScrollListener() {
private int mScrollState;
@ -93,15 +96,8 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
}
}
};
private int mTouchSlop;
private void setControlVisible(boolean visible) {
final FragmentActivity activity = getActivity();
if (activity instanceof BaseSupportActivity) {
((BaseSupportActivity) activity).setControlBarVisibleAnimate(visible);
}
}
private Rect mSystemWindowsInsets = new Rect();
private int mControlBarOffsetPixels;
private PopupMenu mPopupMenu;
protected AbsStatusesFragment() {
@ -160,66 +156,18 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
public void setRefreshing(boolean refreshing) {
if (refreshing == mSwipeRefreshLayout.isRefreshing()) return;
updateRefreshProgressOffset();
mSwipeRefreshLayout.setRefreshing(refreshing);
}
@Override
public final Loader<Data> onCreateLoader(int id, Bundle args) {
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
args.remove(EXTRA_FROM_USER);
return onCreateStatusesLoader(getActivity(), args, fromUser);
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof IControlBarActivity) {
((IControlBarActivity) activity).registerControlBarOffsetListener(this);
}
}
@Override
public final void onLoadFinished(Loader<Data> loader, Data data) {
setRefreshing(false);
final SharedPreferences preferences = getSharedPreferences();
final boolean readFromBottom = preferences.getBoolean(KEY_READ_FROM_BOTTOM, false);
final long lastReadId;
final int lastVisiblePos, lastVisibleTop;
if (readFromBottom) {
lastVisiblePos = mLayoutManager.findLastVisibleItemPosition();
} else {
lastVisiblePos = mLayoutManager.findFirstVisibleItemPosition();
}
if (lastVisiblePos != -1) {
lastReadId = mAdapter.getItemId(lastVisiblePos);
if (readFromBottom) {
lastVisibleTop = mLayoutManager.getChildAt(mLayoutManager.getChildCount() - 1).getTop();
} else {
lastVisibleTop = mLayoutManager.getChildAt(0).getTop();
}
} else {
lastReadId = -1;
lastVisibleTop = 0;
}
mAdapter.setData(data);
if (!(data instanceof IExtendedLoader) || ((IExtendedLoader) data).isFromUser()) {
mAdapter.setLoadMoreIndicatorEnabled(hasMoreData(data));
int pos = -1;
for (int i = 0; i < mAdapter.getItemCount(); i++) {
if (lastReadId == mAdapter.getItemId(i)) {
pos = i;
break;
}
}
if (pos != -1 && mAdapter.isStatus(pos) && (readFromBottom || lastVisiblePos != 0)) {
mLayoutManager.scrollToPositionWithOffset(pos, lastVisibleTop - mLayoutManager.getPaddingTop());
}
}
if (data instanceof IExtendedLoader) {
((IExtendedLoader) data).setFromUser(false);
}
setListShown(true);
}
@Override
public void onLoaderReset(Loader<Data> loader) {
}
public abstract Loader<Data> onCreateStatusesLoader(final Context context, final Bundle args,
final boolean fromUser);
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recycler_view, container, false);
@ -278,6 +226,96 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
super.onDestroyView();
}
@Override
public void onBaseViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onBaseViewCreated(view, savedInstanceState);
mContentView = view.findViewById(R.id.fragment_content);
mProgressContainer = view.findViewById(R.id.progress_container);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_layout);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
}
@Override
public void onDetach() {
final FragmentActivity activity = getActivity();
if (activity instanceof IControlBarActivity) {
((IControlBarActivity) activity).unregisterControlBarOffsetListener(this);
}
super.onDetach();
}
@Override
protected void fitSystemWindows(Rect insets) {
super.fitSystemWindows(insets);
mRecyclerView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
mSystemWindowsInsets.set(insets);
updateRefreshProgressOffset();
}
@Override
public void onControlBarOffsetChanged(IControlBarActivity activity, float offset) {
mControlBarOffsetPixels = Math.round(activity.getControlBarHeight() * (1 - offset));
updateRefreshProgressOffset();
}
@Override
public final Loader<Data> onCreateLoader(int id, Bundle args) {
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
args.remove(EXTRA_FROM_USER);
return onCreateStatusesLoader(getActivity(), args, fromUser);
}
@Override
public final void onLoadFinished(Loader<Data> loader, Data data) {
setRefreshing(false);
final SharedPreferences preferences = getSharedPreferences();
final boolean readFromBottom = preferences.getBoolean(KEY_READ_FROM_BOTTOM, false);
final long lastReadId;
final int lastVisiblePos, lastVisibleTop;
if (readFromBottom) {
lastVisiblePos = mLayoutManager.findLastVisibleItemPosition();
} else {
lastVisiblePos = mLayoutManager.findFirstVisibleItemPosition();
}
if (lastVisiblePos != -1) {
lastReadId = mAdapter.getItemId(lastVisiblePos);
if (readFromBottom) {
lastVisibleTop = mLayoutManager.getChildAt(mLayoutManager.getChildCount() - 1).getTop();
} else {
lastVisibleTop = mLayoutManager.getChildAt(0).getTop();
}
} else {
lastReadId = -1;
lastVisibleTop = 0;
}
mAdapter.setData(data);
if (!(data instanceof IExtendedLoader) || ((IExtendedLoader) data).isFromUser()) {
mAdapter.setLoadMoreIndicatorEnabled(hasMoreData(data));
int pos = -1;
for (int i = 0; i < mAdapter.getItemCount(); i++) {
if (lastReadId == mAdapter.getItemId(i)) {
pos = i;
break;
}
}
if (pos != -1 && mAdapter.isStatus(pos) && (readFromBottom || lastVisiblePos != 0)) {
mLayoutManager.scrollToPositionWithOffset(pos, lastVisibleTop - mLayoutManager.getPaddingTop());
}
}
if (data instanceof IExtendedLoader) {
((IExtendedLoader) data).setFromUser(false);
}
setListShown(true);
}
@Override
public void onLoaderReset(Loader<Data> loader) {
}
public abstract Loader<Data> onCreateStatusesLoader(final Context context, final Bundle args,
final boolean fromUser);
@Override
public void onGapClick(GapViewHolder holder, int position) {
final ParcelableStatus status = mAdapter.getStatus(position);
@ -349,27 +387,6 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
triggerRefresh();
}
@Override
public void onBaseViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onBaseViewCreated(view, savedInstanceState);
mContentView = view.findViewById(R.id.fragment_content);
mProgressContainer = view.findViewById(R.id.progress_container);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_layout);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
}
@Override
protected void fitSystemWindows(Rect insets) {
super.fitSystemWindows(insets);
mRecyclerView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
float density = getResources().getDisplayMetrics().density;
// 40: SwipeRefreshLayout.CIRCLE_DIAMETER
final int swipeStart = insets.top - Math.round(40 * density);
// 64: SwipeRefreshLayout.DEFAULT_CIRCLE_TARGET
final int swipeDistance = Math.round(64 * density);
mSwipeRefreshLayout.setProgressViewOffset(false, swipeStart, swipeStart + swipeDistance);
}
@Override
public boolean scrollToStart() {
final AsyncTwitterWrapper twitter = getTwitterWrapper();
@ -378,6 +395,7 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
twitter.clearUnreadCountAsync(tabPosition);
}
mRecyclerView.smoothScrollToPosition(0);
// mRecyclerView.scrollToPosition(0);
return true;
}
@ -401,11 +419,27 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
protected abstract void onLoadMoreStatuses();
private void setControlVisible(boolean visible) {
final FragmentActivity activity = getActivity();
if (activity instanceof BaseSupportActivity) {
((BaseSupportActivity) activity).setControlBarVisibleAnimate(visible);
}
}
private void setListShown(boolean shown) {
mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE);
mSwipeRefreshLayout.setVisibility(shown ? View.VISIBLE : View.GONE);
}
private void updateRefreshProgressOffset() {
if (mSystemWindowsInsets.top == 0 || mSwipeRefreshLayout == null || isRefreshing()) return;
// 40: SwipeRefreshLayout.CIRCLE_DIAMETER
final float density = getResources().getDisplayMetrics().density;
final int swipeStart = (mSystemWindowsInsets.top - mControlBarOffsetPixels) - Math.round(40 * density);
// 64: SwipeRefreshLayout.DEFAULT_CIRCLE_TARGET
final int swipeDistance = Math.round(64 * density);
mSwipeRefreshLayout.setProgressViewOffset(true, swipeStart, swipeStart + swipeDistance);
}
protected final class StatusesBusCallback {

View File

@ -207,7 +207,8 @@ public class DirectMessagesConversationFragment extends BaseSupportFragment impl
mUserQuery = (EditText) actionBarView.findViewById(R.id.user_query);
mQueryButton = actionBarView.findViewById(R.id.query_button);
final List<ParcelableAccount> accounts = ParcelableAccount.getAccountsList(activity, false);
final AccountsSpinnerAdapter accountsSpinnerAdapter = new AccountsSpinnerAdapter(mAccountSpinner.getContext(), R.layout.spinner_item_account_icon);
final AccountsSpinnerAdapter accountsSpinnerAdapter = new AccountsSpinnerAdapter(
actionBar.getThemedContext(), R.layout.spinner_item_account_icon);
accountsSpinnerAdapter.setDropDownViewResource(R.layout.list_item_user);
accountsSpinnerAdapter.addAll(accounts);
mAccountSpinner.setAdapter(accountsSpinnerAdapter);

View File

@ -656,6 +656,7 @@ public class StatusFragment extends BaseSupportFragment
cardView.setCardBackgroundColor(mCardBackgroundColor);
}
final StatusViewHolder holder = new StatusViewHolder(this, view);
holder.setupViewOptions();
holder.setOnClickListeners();
return holder;
}

View File

@ -18,15 +18,23 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
tools:menu="menu_media_viewer_image_page"
android:layout_height="match_parent">
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
tools:menu="menu_media_viewer_image_page"
android:layout_height="match_parent">
<org.mariotaku.twidere.view.MediaViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>
<View
android:id="@+id/media_status"
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="128dp"
android:background="#f00"/>
</FrameLayout>