Edit:
package com.walkindeep.teammanagerpreview;
import android.content.Context;
import android.os.Bundle;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import com.dexafree.materialList.card.Card;
import com.dexafree.materialList.card.CardProvider;
import com.dexafree.materialList.card.OnActionClickListener;
import com.dexafree.materialList.card.action.TextViewAction;
import com.dexafree.materialList.listeners.OnDismissCallback;
import com.dexafree.materialList.view.MaterialListView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class MyTaskActivity extends NavigationActivity {
private Context mContext = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*全局导航栏*/
LayoutInflater inflater = (LayoutInflater) this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View contentView = inflater.inflate(R.layout.activity_task, null, false);
drawer.addView(contentView, 0);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.floatingActionButtionTask);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
View bottomSheet = findViewById(R.id.bottom_sheet);
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
});
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
/*cardView*/
// initCard();
final User user = User.init("xxx", "xxx");
updateTask(user);
/*下滑刷新*/
final SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.SwipeRefreshLayout);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
updateTask(user, swipeRefreshLayout);
}
});
}
/*更新任务数据*/
private void updateTask(User user, SwipeRefreshLayout swipeRefreshLayout) {
DataHandler dataHandler = new DataHandler();
dataHandler.getData("issues.json?assigned_to_id=me" + "&status_id=1", this, user);
swipeRefreshLayout.setRefreshing(false);
}
/*更新任务数据*/
private void updateTask(User user) {
DataHandler dataHandler = new DataHandler();
dataHandler.getData("issues.json?assigned_to_id=me" + "&status_id=1", this, user);
}
private Card[] jsonToCards(JSONObject userIssuesJSONObjectTemp) {
JSONArray userIssuesJSONArray = null;
try {
userIssuesJSONArray = userIssuesJSONObjectTemp.getJSONArray("issues");
} catch (JSONException e) {
e.printStackTrace();
}
List<Card> cards = new ArrayList<>();
/*用于存储所有issue的list*/
List<Issue> issueList = Issue.getIssueList();
issueList.clear();
for (int i = 0; i < userIssuesJSONArray.length(); i++) {
try {
/*创建issue类*/
Issue issue = new Issue(userIssuesJSONArray.getJSONObject(i).getString("subject"), userIssuesJSONArray.getJSONObject(i).getString("description"), userIssuesJSONArray.getJSONObject(i).getInt("id"));
issueList.add(issue);
Card card = new Card.Builder(this)
.withProvider(new CardProvider())
.setLayout(R.layout.material_basic_buttons_card)
.setTitle(issue.getSubject())
.setDescription(issue.getDescription())
.addAction(R.id.left_text_button, new TextViewAction(this)
.setText("按钮1")
.setTextResourceColor(R.color.black_button)
.setListener(new OnActionClickListener() {
#Override
public void onActionClicked(View view, Card card) {
Toast.makeText(mContext, "You have pressed the left button", Toast.LENGTH_SHORT).show();
}
}))
.addAction(R.id.right_text_button, new TextViewAction(this)
.setText("按钮2")
.setTextResourceColor(R.color.accent_material_dark)
.setListener(new OnActionClickListener() {
#Override
public void onActionClicked(View view, Card card) {
Toast.makeText(mContext, "You have pressed the right button", Toast.LENGTH_SHORT).show();
}
}))
.endConfig()
.build();
card.setTag(issue);//设置卡片和issue关联
cards.add(card);
} catch (JSONException e) {
e.printStackTrace();
}
}
return cards.toArray(new Card[cards.size()]);
}
public void setCardsToUI(Card[] cards) {
final MaterialListView mListView = (MaterialListView) findViewById(R.id.material_listview);
mListView.getAdapter().clearAll();
for (int i = 0; i < cards.length; i++) {
mListView.getAdapter().add(cards[i]);
/*设置卡片可以滑动删除*/
cards[i].setDismissible(true);
}
/*设置滑动删除操作*/
mListView.setOnDismissCallback(new OnDismissCallback() {
public void onDismiss(final Card card, final int position) {
Snackbar.make(mListView, "已标记完成", Snackbar.LENGTH_LONG)
.setCallback(new Snackbar.Callback() {
#Override
public void onDismissed(Snackbar snackbar, int event) {
if (event == DISMISS_EVENT_ACTION) {//do nothing but recover card
mListView.getAdapter().add(position, card);
} else {
Issue issue = (Issue) card.getTag();
issue.setStatusid(3);
issue.pushStatusName(mContext);
List<Issue> issueList = Issue.getIssueList();
}
}
})
.setAction("撤销", new View.OnClickListener() {
#Override
public void onClick(View v) {
}
})
.show();
}
});
}
class DataHandler extends AbstractDataQuery {
#Override
protected void work(JSONObject userIssuesJSONObject) {
Card[] cards = jsonToCards(userIssuesJSONObject);
setCardsToUI(cards);
}
}
}
When click the floating action button "+", the bottomsheet show up like this:
Here is the activity_task.xml file:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
android:fitsSystemWindows="true"
tools:context=".MyTaskActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_task" />
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:id="#+id/bottom_sheet"
android:layout_height="wrap_content"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="#+id/buildProjectButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/buildProject" />
<Button
android:id="#+id/buildTaskButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/buildTask" />
</LinearLayout>
</ScrollView>
<android.support.design.widget.FloatingActionButton
android:id="#+id/floatingActionButtionTask"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_input_add" />
</android.support.design.widget.CoordinatorLayout>
Everything seems OK, but when I click above the bottomsheet, it doesn't disappear totally as I expect:
What's wrong?
"By attaching a BottomSheetBehavior to a child View of a CoordinatorLayout (i.e., adding app:layout_behavior=”android.support.design.widget.BottomSheetBehavior”), you’ll automatically get the appropriate touch detection to transition between five state...".Try changing your Linear Layout to Frame Layout will do.
Try to use like this.
<FrameLayout
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000"
app:behavior_hideable="true"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<Button
android:id="#+id/buildProjectButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/buildProject" />
<Button
android:id="#+id/buildTaskButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/buildTask" />
</FrameLayout>
Modify your code as this.
View bottomSheet = findViewById(R.id.bottom_sheet);
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
// React to state change
Log.e("onStateChanged", "onStateChanged:" + newState);
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
// Hide your state here.
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
// React to dragging events
Log.e("onSlide", "onSlide");
}
});
EDIT 1:
Bottom sheets behavior is not hideable by default. You need to add this.
bottomSheetBehavior.setHideable(true);
You are using a Persistent bottom sheet, this type of bottom sheet responds mainly to drag events i.e. you have to close it by dragging it down. If you want a bottom sheet that responds to clicking outside the dialog, consider Modal bottom sheet.
Alternatively, you can also use the fab to toggle the state of the bottom sheet i.e onClick of the fab it should expand the sheet if collapsed or collapse it if expanded.
Related
I'm developing wordpress android app which loads Wordpress post data in android webview. I'm using retrofit & JSON API to fetch data from my Wordpress site. My app worked fine in android API LEVEL 26 but the problem is I need API 28+ to upload to google play store. I migrated to androidx API LEVEL 29. post were not getting loaded showing ERR_CLEARTEXT_NOT_PERMITTED so I used "android:usesCleartextTraffic=true" post was loading but the problem is HTML entities like –,“,’ etc failed to decode and decoded as & and remaining lines of the post are not loaded after this. I dint use "android:usesCleartextTraffic=true" in API LEVEL 26 but it works fine without any error. I'm searching a solution for my problem I didn't find satisfying answers anywhere. I'm stuck at this point. So I'm trying alternative method for "android:usesCleartextTraffic=true". I have "text to speech" function in my app its working absolutely fine I mean its reading entire post which is not visible in android webview. Kindly suggest. Please find the code for your reference.
WEBVIEW SCREESHOT
this is my postdetails activity
Postdetails.java
package ak.wp.meto.activity;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.fragment.app.FragmentManager;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.text.Html;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import ak.wp.meto.R;
import ak.wp.meto.adapters.CommentsAdapter;
import ak.wp.meto.api.http.ApiUtils;
import ak.wp.meto.api.models.posts.post.CommentsAndReplies;
import ak.wp.meto.api.models.posts.post.PostDetails;
import ak.wp.meto.api.params.HttpParams;
import ak.wp.meto.data.constant.AppConstant;
import ak.wp.meto.data.sqlite.FavouriteDbController;
import ak.wp.meto.fragment.WriteACommentFragment;
import ak.wp.meto.listeners.ListItemClickListener;
import ak.wp.meto.models.FavouriteModel;
import ak.wp.meto.utility.ActivityUtils;
import ak.wp.meto.utility.AppUtils;
import ak.wp.meto.utility.TtsEngine;
import ak.wp.meto.webengine.WebEngine;
import ak.wp.meto.webengine.WebListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class PostDetailsActivity extends BaseActivity implements WriteACommentFragment.OnCompleteListener {
// Variables
private Activity mActivity;
private Context mContext;
// init views
private RelativeLayout lytPostDetailsView, lytCommentDetails;
private int clickedPostId;
private ImageView imgPost;
private TextView tvPostTitle, tvPostAuthor, tvPostDate, tvCommnentList;
private WebView webView;
private FloatingActionButton fabWriteAComment;
private ImageButton imgBtnSpeaker, imgBtnFav, imgBtnShare;
private PostDetails model = null;
// Favourites view
private List<FavouriteModel> favouriteList;
private FavouriteDbController favouriteDbController;
private boolean isFavourite = false;
// Comments view
private List<CommentsAndReplies> commentList;
private List<CommentsAndReplies> zeroParentComments;
List<CommentsAndReplies> onlyThreeComments;
private int mPerPage = 5;
private RecyclerView rvComments;
private CommentsAdapter commentsAdapter = null;
// Text to speech
private TtsEngine ttsEngine;
private boolean isTtsPlaying = false;
private String ttsText;
private WebEngine webEngine;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initVar();
initView();
initFunctionality();
initListener();
}
private void initVar() {
mActivity = PostDetailsActivity.this;
mContext = mActivity.getApplicationContext();
// Favourites view
favouriteList = new ArrayList<>();
// Comments view
commentList = new ArrayList<>();
zeroParentComments = new ArrayList<>();
onlyThreeComments = new ArrayList<>();
Intent intent = getIntent();
if (intent != null) {
clickedPostId = getIntent().getIntExtra(AppConstant.BUNDLE_KEY_POST_ID, 0);
}
}
private void initView() {
setContentView(R.layout.activity_post_details);
lytPostDetailsView = (RelativeLayout) findViewById(R.id.lyt_post_details);
lytCommentDetails = (RelativeLayout) findViewById(R.id.lyt_comment_list);
//lytParentView.setVisibility(View.GONE);
imgPost = (ImageView) findViewById(R.id.post_img);
tvPostTitle = (TextView) findViewById(R.id.title_text);
tvPostAuthor = (TextView) findViewById(R.id.post_author);
tvPostDate = (TextView) findViewById(R.id.date_text);
imgBtnSpeaker = (ImageButton) findViewById(R.id.imgBtnSpeaker);
imgBtnFav = (ImageButton) findViewById(R.id.imgBtnFavourite);
imgBtnShare = (ImageButton) findViewById(R.id.imgBtnShare);
initWebEngine();
tvCommnentList = (TextView) findViewById(R.id.comment_count);
fabWriteAComment = (FloatingActionButton) findViewById(R.id.fab_new_comment);
rvComments = (RecyclerView) findViewById(R.id.rvComments);
rvComments.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
initLoader();
initToolbar();
enableBackButton();
}
public void initWebEngine() {
webView = (WebView) findViewById(R.id.web_view);
webEngine = new WebEngine(webView, mActivity);
webEngine.initWebView();
webEngine.initListeners(new WebListener() {
#Override
public void onStart() {
initLoader();
}
#Override
public void onLoaded() {
hideLoader();
}
#Override
public void onProgress(int progress) {
}
#Override
public void onNetworkError() {
showEmptyView();
}
#Override
public void onPageTitle(String title) {
}
});
}
private void initFunctionality() {
favouriteDbController = new FavouriteDbController(mContext);
favouriteList.addAll(favouriteDbController.getAllData());
for (int i = 0; i < favouriteList.size(); i++) {
if (favouriteList.get(i).getPostId() == clickedPostId) {
isFavourite = true;
break;
}
}
ttsEngine = new TtsEngine(mActivity);
commentsAdapter = new CommentsAdapter(mActivity, (ArrayList) commentList, (ArrayList) onlyThreeComments);
rvComments.setAdapter(commentsAdapter);
showLoader();
loadPostDetails();
// show full-screen ads
// AdUtils.getInstance(mContext).showFullScreenAd();
}
public void setFavImage() {
if (isFavourite) {
imgBtnFav.setImageDrawable(ContextCompat.getDrawable(mActivity, R.drawable.ic_book));
} else {
imgBtnFav.setImageDrawable(ContextCompat.getDrawable(mActivity, R.drawable.ic_un_book));
}
}
public void initListener() {
imgBtnSpeaker.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (model != null) {
toggleTtsPlay();
}
}
});
imgBtnFav.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (model != null) {
isFavourite = !isFavourite;
if (isFavourite) {
String imgUrl = null;
if (model.getEmbedded().getWpFeaturedMedias().size() >= 1) {
imgUrl = model.getEmbedded().getWpFeaturedMedias().get(0).getMediaDetails().getSizes().getFullSize().getSourceUrl();
}
favouriteDbController.insertData(
model.getID().intValue(),
imgUrl,
model.getTitle().getRendered(),
model.getOldDate(),
model.getEmbedded().getWpTerms().get(0).get(0).getName()
);
} else {
favouriteDbController.deleteFav(clickedPostId);
}
setFavImage();
}
}
});
imgBtnShare.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (model != null) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, model.getPageUrl());
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to)));
}
}
});
commentsAdapter.setItemClickListener(new ListItemClickListener() {
#Override
public void onItemClick(int position, View view) {
int id = view.getId();
CommentsAndReplies clickedComment = zeroParentComments.get(position);
switch (id) {
case R.id.list_item:
ActivityUtils.getInstance().invokeCommentDetails(mActivity, CommentDetailsActivity.class, (ArrayList) commentList, clickedPostId, clickedComment, false, false);
break;
case R.id.reply_text:
ActivityUtils.getInstance().invokeCommentDetails(mActivity, CommentDetailsActivity.class, (ArrayList) commentList, clickedPostId, clickedComment, true, false);
break;
default:
break;
}
}
});
tvCommnentList.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ActivityUtils.getInstance().invokeCommentList(mActivity,
CommentListActivity.class,
(ArrayList) commentList,
(ArrayList) zeroParentComments,
clickedPostId,
false);
}
});
fabWriteAComment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager manager = getSupportFragmentManager();
WriteACommentFragment dialog = WriteACommentFragment.newInstance(clickedPostId, AppConstant.THIS_IS_COMMENT);
dialog.show(manager, AppConstant.BUNDLE_KEY_DIALOG_FRAGMENT);
}
});
}
public void loadPostDetails() {
ApiUtils.getApiInterface().getPostDetails(clickedPostId).enqueue(new Callback<PostDetails>() {
#Override
public void onResponse(Call<PostDetails> call, Response<PostDetails> response) {
if (response.isSuccessful()) {
// bind data
model = response.body();
PostDetails m = model;
// visible parent view
lytPostDetailsView.setVisibility(View.VISIBLE);
// visible comments button
fabWriteAComment.setVisibility(View.VISIBLE);
loadCommentsAndReplies(model.getLinks().getRepliesList().get(0).getHref());
setFavImage();
tvPostTitle.setText(Html.fromHtml(model.getTitle().getRendered()));
String imgUrl = null;
if (model.getEmbedded().getWpFeaturedMedias().size() > 0) {
if (model.getEmbedded().getWpFeaturedMedias().get(0).getMediaDetails() != null) {
if (model.getEmbedded().getWpFeaturedMedias().get(0).getMediaDetails().getSizes().getFullSize().getSourceUrl() != null) {
imgUrl = model.getEmbedded().getWpFeaturedMedias().get(0).getMediaDetails().getSizes().getFullSize().getSourceUrl();
}
}
}
if (imgUrl != null) {
Glide.with(getApplicationContext())
.load(imgUrl)
.into(imgPost);
}
String author = null;
if (model.getEmbedded().getAuthors().size() >= 1) {
author = model.getEmbedded().getAuthors().get(0).getName();
}
if (author == null) {
author = getString(R.string.admin);
}
tvPostAuthor.setText(Html.fromHtml(author));
String oldDate = model.getOldDate();
String newDate = AppUtils.getFormattedDate(oldDate);
if (newDate != null) {
tvPostDate.setText(Html.fromHtml(newDate));
}
String contentText = model.getContent().getRendered();
ttsText = new StringBuilder(Html.fromHtml(model.getTitle().getRendered())).append(AppConstant.DOT).append(Html.fromHtml(model.getContent().getRendered())).toString();
webView.loadData(contentText, "text/html", "UTF-8"); //comment
contentText = new StringBuilder().append(AppConstant.CSS_PROPERTIES).append(contentText).toString();
webEngine.loadHtml(contentText);
} else {
showEmptyView();
}
}
#Override
public void onFailure(Call<PostDetails> call, Throwable t) {
t.printStackTrace();
// hide common loader
hideLoader();
// show empty view
showEmptyView();
}
});
}
public void loadCommentsAndReplies(final String commentsAndRepliesLink) {
ApiUtils.getApiInterface().getCommentsAndReplies(commentsAndRepliesLink, mPerPage).enqueue(new Callback<List<CommentsAndReplies>>() {
#Override
public void onResponse(Call<List<CommentsAndReplies>> call, Response<List<CommentsAndReplies>> response) {
if (response.isSuccessful()) {
int totalItems = Integer.parseInt(response.headers().get(HttpParams.HEADER_TOTAL_ITEM));
int totalPages = Integer.parseInt(response.headers().get(HttpParams.HEADER_TOTAL_PAGE));
if (totalPages > 1) {
mPerPage = mPerPage * totalPages;
loadCommentsAndReplies(commentsAndRepliesLink);
} else {
if (!commentList.isEmpty() || !zeroParentComments.isEmpty() || !onlyThreeComments.isEmpty()) {
commentList.clear();
zeroParentComments.clear();
onlyThreeComments.clear();
}
commentList.addAll(response.body());
lytCommentDetails.setVisibility(View.VISIBLE);
if (commentList.size() > 0) {
for (CommentsAndReplies commentsAndReplies : commentList) {
if (commentsAndReplies.getParent().intValue() == 0) {
zeroParentComments.add(commentsAndReplies);
}
}
if (zeroParentComments.size() >= 3) {
for (int i = 0; i < 3; i++) {
onlyThreeComments.add(zeroParentComments.get(i));
}
} else {
for (CommentsAndReplies commentsAndReplies : zeroParentComments) {
onlyThreeComments.add(commentsAndReplies);
}
}
commentsAdapter.notifyDataSetChanged();
tvCommnentList.setText(String.format(getString(R.string.all_comment), commentList.size()));
tvCommnentList.setClickable(true);
} else {
tvCommnentList.setClickable(false);
}
}
}
}
#Override
public void onFailure(Call<List<CommentsAndReplies>> call, Throwable t) {
showEmptyView();
t.printStackTrace();
}
});
}
private void toggleTtsPlay() {
if (isTtsPlaying) {
ttsEngine.releaseEngine();
isTtsPlaying = false;
} else {
ttsEngine.startEngine(ttsText);
isTtsPlaying = true;
}
toggleTtsView();
}
private void toggleTtsView() {
if (isTtsPlaying) {
imgBtnSpeaker.setImageDrawable(getResources().getDrawable(R.drawable.ic_speaker_stop));
} else {
imgBtnSpeaker.setImageDrawable(getResources().getDrawable(R.drawable.ic_speaker));
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
finish();
}
#Override
protected void onStop() {
super.onStop();
ttsEngine.releaseEngine();
}
#Override
protected void onDestroy() {
super.onDestroy();
ttsEngine.releaseEngine();
model = null;
}
#Override
protected void onResume() {
super.onResume();
if (isTtsPlaying) {
isTtsPlaying = false;
imgBtnSpeaker.setImageDrawable(getResources().getDrawable(R.drawable.ic_speaker));
}
}
#Override
public void onComplete(Boolean isCommentSuccessful, CommentsAndReplies commentsAndReplies) {
if (isCommentSuccessful) {
loadCommentsAndReplies(model.getLinks().getRepliesList().get(0).getHref());
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
if (requestCode == AppConstant.REQUEST_CODE_COMMENT) {
if (data == null) {
return;
}
boolean isCommentSuccessful = CommentListActivity.wasCommentSuccessful(data);
if (isCommentSuccessful) {
loadCommentsAndReplies(model.getLinks().getRepliesList().get(0).getHref());
}
}
}
}
activity_post_details.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
android:background="#color/white"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="#+id/post_img"
android:layout_width="match_parent"
android:layout_height="#dimen/margin_250dp"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="#color/white"
app:layout_collapseMode="parallax" />
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="#+id/imgBtnSpeaker"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:layout_toLeftOf="#id/imgBtnFavourite"
android:padding="5dp"
android:scaleType="centerInside"
android:src="#drawable/ic_speaker" />
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/content_post_details" />
<include layout="#layout/content_comments" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab_new_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/activity_vertical_margin"
android:src="#drawable/ic_fab"
android:visibility="gone" />
<include layout="#layout/view_common_loader" /> </androidx.coordinatorlayout.widget.CoordinatorLayout>
content_post_details.xml
<?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:id="#+id/lyt_post_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:visibility="gone">
<LinearLayout
android:id="#+id/li_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/margin_8dp"
android:layout_marginTop="#dimen/margin_8dp"
android:orientation="horizontal"
android:weightSum="1">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/margin_20dp"
android:layout_weight="0.5"
android:gravity="center_vertical"
android:padding="#dimen/margin_8dp">
<ImageView
android:id="#+id/author_image"
android:layout_width="#dimen/margin_30dp"
android:layout_height="#dimen/margin_30dp"
android:background="#drawable/ic_author" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/margin_20dp"
android:layout_weight="0.5"
android:gravity="center_vertical"
android:padding="#dimen/margin_8dp">
</LinearLayout>
</LinearLayout>
<View
android:id="#+id/viewDivider"
android:layout_width="match_parent"
android:layout_height="0.7dp"
android:layout_below="#id/li_layout"
android:layout_marginLeft="#dimen/margin_15dp"
android:layout_marginRight="#dimen/margin_15dp"
android:background="#color/toolbar_boarder" />
<TextView
android:id="#+id/title_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/viewDivider"
android:layout_margin="#dimen/margin_8dp"
android:textColor="#color/black"
android:textSize="18sp"
android:textStyle="bold"
tools:text="This is sample text do yoy know that it supports multi-line" />
<WebView
android:id="#+id/web_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/title_text"
android:layout_margin="#dimen/margin_8dp"
android:paddingBottom="#dimen/margin_8dp" />
</RelativeLayout>
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
The application crashes with an error stating that the Recyclerview is being called on a null object. However I can't seem to pinpoint what is causing this issue. Any help would be very much appreciated. If anymore code is needed, do let me know and I'll edit it in.
Logcat error:
2019-10-30 23:59:15.235 10878-10878/com.example.zaphk.studenthelperapplication3 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.zaphk.studenthelperapplication3, PID: 10878
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.zaphk.studenthelperapplication3/com.example.zaphk.studenthelperapplication3.view.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setLayoutManager(android.support.v7.widget.RecyclerView$LayoutManager)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2861)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2943)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1630)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6626)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setLayoutManager(android.support.v7.widget.RecyclerView$LayoutManager)' on a null object reference
at com.example.zaphk.studenthelperapplication3.view.MainActivity.onCreate(MainActivity.java:65)
at android.app.Activity.performCreate(Activity.java:7032)
at android.app.Activity.performCreate(Activity.java:7023)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1236)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2814)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2943)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1630)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6626)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
MainActivity.java
package com.example.zaphk.studenthelperapplication3.view;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import com.example.zaphk.studenthelperapplication3.database.DatabaseHelper;
import com.example.zaphk.studenthelperapplication3.database.model.Note;
import com.example.zaphk.studenthelperapplication3.utils.MyDividerItemDecoration;
import com.example.zaphk.studenthelperapplication3.utils.RecyclerTouchListener;
import com.example.zaphk.studenthelperapplication3.R;
public class MainActivity extends AppCompatActivity {
private NotesAdapter mAdapter;
private List<Note> notesList = new ArrayList<>();
private CoordinatorLayout coordinatorLayout;
private RecyclerView recyclerView;
private TextView noNotesView;
private DatabaseHelper db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notes);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
coordinatorLayout = findViewById(R.id.coordinator_layout);
recyclerView = findViewById(R.id.recycler_view);
noNotesView = findViewById(R.id.empty_notes_view);
db = new DatabaseHelper(this);
notesList.addAll(db.getAllNotes());
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showNoteDialog(false, null, -1);
}
});
mAdapter = new NotesAdapter(this, notesList);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16));
recyclerView.setAdapter(mAdapter);
toggleEmptyNotes();
/**
* On long press on RecyclerView item, open alert dialog
* with options to choose
* Edit and Delete
* */
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this,
recyclerView, new RecyclerTouchListener.ClickListener() {
#Override
public void onClick(View view, final int position) {
}
#Override
public void onLongClick(View view, int position) {
showActionsDialog(position);
}
}));
}
/**
* Inserting new note in db
* and refreshing the list
*/
private void createNote(String note) {
// inserting note in db and getting
// newly inserted note id
long id = db.insertNote(note);
// get the newly inserted note from db
Note n = db.getNote(id);
if (n != null) {
// adding new note to array list at 0 position
notesList.add(0, n);
// refreshing the list
mAdapter.notifyDataSetChanged();
toggleEmptyNotes();
}
}
/**
* Updating note in db and updating
* item in the list by its position
*/
private void updateNote(String note, int position) {
Note n = notesList.get(position);
// updating note text
n.setNote(note);
// updating note in db
db.updateNote(n);
// refreshing the list
notesList.set(position, n);
mAdapter.notifyItemChanged(position);
toggleEmptyNotes();
}
/**
* Deleting note from SQLite and removing the
* item from the list by its position
*/
private void deleteNote(int position) {
// deleting the note from db
db.deleteNote(notesList.get(position));
// removing the note from the list
notesList.remove(position);
mAdapter.notifyItemRemoved(position);
toggleEmptyNotes();
}
/**
* Opens dialog with Edit - Delete options
* Edit - 0
* Delete - 0
*/
private void showActionsDialog(final int position) {
CharSequence colors[] = new CharSequence[]{"Edit", "Delete"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Choose option");
builder.setItems(colors, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
showNoteDialog(true, notesList.get(position), position);
} else {
deleteNote(position);
}
}
});
builder.show();
}
/**
* Shows alert dialog with EditText options to enter / edit
* a note.
* when shouldUpdate=true, it automatically displays old note and changes the
* button text to UPDATE
*/
private void showNoteDialog(final boolean shouldUpdate, final Note note, final int position) {
LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext());
View view = layoutInflaterAndroid.inflate(R.layout.note_dialog, null);
AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(MainActivity.this);
alertDialogBuilderUserInput.setView(view);
final EditText inputNote = view.findViewById(R.id.note);
TextView dialogTitle = view.findViewById(R.id.dialog_title);
dialogTitle.setText(!shouldUpdate ? getString(R.string.lbl_new_note_title) : getString(R.string.lbl_edit_note_title));
if (shouldUpdate && note != null) {
inputNote.setText(note.getNote());
}
alertDialogBuilderUserInput
.setCancelable(false)
.setPositiveButton(shouldUpdate ? "update" : "save", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogBox, int id) {
}
})
.setNegativeButton("cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogBox, int id) {
dialogBox.cancel();
}
});
final AlertDialog alertDialog = alertDialogBuilderUserInput.create();
alertDialog.show();
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Show toast message when no text is entered
if (TextUtils.isEmpty(inputNote.getText().toString())) {
Toast.makeText(MainActivity.this, "Enter note!", Toast.LENGTH_SHORT).show();
return;
} else {
alertDialog.dismiss();
}
// check if user updating note
if (shouldUpdate && note != null) {
// update note by it's id
updateNote(inputNote.getText().toString(), position);
} else {
// create new note
createNote(inputNote.getText().toString());
}
}
});
}
/**
* Toggling list and empty notes view
*/
private void toggleEmptyNotes() {
// you can check notesList.size() > 0
if (db.getNotesCount() > 0) {
noNotesView.setVisibility(View.GONE);
} else {
noNotesView.setVisibility(View.VISIBLE);
}
}
}
NotesAdapter.java
package com.example.zaphk.studenthelperapplication3.view;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import com.example.zaphk.studenthelperapplication3.calendar.database.Calendar;
import com.example.zaphk.studenthelperapplication3.database.model.Note;
import com.example.zaphk.studenthelperapplication3.R;
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.MyViewHolder> {
private Context context;
private List<Note> notesList;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView note;
public TextView dot;
public TextView timestamp;
public MyViewHolder(View view) {
super(view);
note = view.findViewById(R.id.note);
dot = view.findViewById(R.id.dot);
timestamp = view.findViewById(R.id.timestamp);
}
}
public NotesAdapter(Context context, List<Note> notesList) {
this.context = context;
this.notesList = notesList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.note_list_row, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Note note = notesList.get(position);
holder.note.setText(note.getNote());
// Displaying dot from HTML character code
holder.dot.setText(Html.fromHtml("•"));
// Formatting and displaying timestamp
holder.timestamp.setText(formatDate(note.getTimestamp()));
}
#Override
public int getItemCount() {
return notesList.size();
}
/**
* Formatting timestamp to `MMM d` format
* Input: 2018-02-21 00:15:42
* Output: Feb 21
*/
private String formatDate(String dateStr) {
try {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = fmt.parse(dateStr);
SimpleDateFormat fmtOut = new SimpleDateFormat("MMM d");
return fmtOut.format(date);
} catch (ParseException e) {
}
return "";
}
}
activity_notes.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/coordinator_layout"
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="com.example.zaphk.studenthelperapplication3.view.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main_timetable" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#drawable/ic_add_white_24dp" />
</android.support.design.widget.CoordinatorLayout>
note_list_row.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/coordinator_layout"
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="com.example.zaphk.studenthelperapplication3.view.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main_timetable" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#drawable/ic_add_white_24dp" />
</android.support.design.widget.CoordinatorLayout>
content_main_timetable.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="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".activities.TimetableActivity"
tools:showIn="#layout/app_bar_main">
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/baseline_add_white_24"
tools:layout_editor_absoluteX="339dp"
tools:layout_editor_absoluteY="546dp" />
</FrameLayout>
There is no RecyclerView in your layout file, so when you call findViewById, no view is found, and your recyclerView is null, which is the reason for your null pointer exception.
In content_main_timetable did you mean RecyclerView instead of ViewPager? Replacing the view pager with a recycler view called recycler_view would fix your problem.
Your layout doesn't have a recyclerView. Which is why, findViewById returns a null. Your recyclerView is null, so you can't really set a layoutmanager on it. Fix your activity layout to include a recyclerview.
I have a problem within my code that seems to me as it is working but only in the given situation where On_Click Events within fragments are firing when using tab and enter key but not mouse click. I am using the emulator through android studio SDK23 for the emulater. When I test it on my phone sdk26 it does not allow the tap to click anything within the fragment. I feel like I may be missing something very simple.
Here is my Activity:
package com.wgu.c196.testproject;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import com.wgu.c196.testproject.database.TermDatabase;
import com.wgu.c196.testproject.fragment.TestFragment;
public class MainActivity extends AppCompatActivity implements
NavigationView.OnNavigationItemSelectedListener,
TestFragment.OnListFragmentInteractionListener{
private DrawerLayout drawer;
private FloatingActionButton fab;
private TextView fragTitle;
public DrawerLayout getDrawer() {
return drawer;
}
public void setDrawer(DrawerLayout drawer) {
this.drawer = drawer;
}
public TextView getFragTitle() {
return fragTitle;
}
public void setFragTitle(TextView fragTitle) {
this.fragTitle = fragTitle;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
drawer = findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
Fragment testFragment = new TestFragment();
replaceFragment(testFragment );
fragTitle = findViewById(R.id.fragment_title);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
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.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
item.setChecked(true);
drawer.closeDrawers();
fab.show();
switch(item.getItemId()) {
case R.id.nav_terms:
case R.id.nav_courses:
case R.id.nav_assessment:
case R.id.nav_scheduler:
case R.id.nav_alerts:
case R.id.nav_share:
case R.id.nav_send:
default:
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
#Override
public void onDestroy(){
TermDatabase.destroyInstance();
super.onDestroy();
}
public void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
// Begin the transaction
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_main_placeholder, fragment, fragment.toString());
fragmentTransaction.addToBackStack(fragment.toString());
fragmentTransaction.commit();
}
#Override
public void onListFragmentInteraction(View view) {
}
}
My Fragment:
package com.wgu.c196.testproject.fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
import com.wgu.c196.testproject.MainActivity;
import com.wgu.c196.testproject.R;
public class TestFragment extends Fragment {
// TODO: Customize parameter argument names
private static final String ARG_COLUMN_COUNT = "column-count";
// TODO: Customize parameters
private int mColumnCount = 1;
private OnListFragmentInteractionListener mListener;
private View mView;
public View getView() {
return mView;
}
public void setView(View mView) {
this.mView = mView;
}
ragment (e.g. upon screen orientation changes).
*/
public TestFragment() {
}
// TODO: Customize parameter initialization
#SuppressWarnings("unused")
public static TestFragment newInstance(int columnCount) {
TestFragment fragment = new TestFragment();
Bundle args = new Bundle();
args.putInt(ARG_COLUMN_COUNT, columnCount);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_test, container, false);
((MainActivity) mView.getContext()).getFragTitle().setText("Test Button");
Button btn = mView.findViewById(R.id.d_button_id);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Something clicked me in Fragment!", Toast.LENGTH_SHORT).show();
}
});
btn.setOnTouchListener(new View.OnTouchListener() {
#Override public boolean onTouch(View v, MotionEvent event) {
Toast.makeText(v.getContext(), "Something touched me in Fragment!", Toast.LENGTH_SHORT).show();
return false;
}
});
return mView;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnListFragmentInteractionListener) {
mListener = (OnListFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnListFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
#Override
public void onDestroy(){
super.onDestroy();
}
public interface OnListFragmentInteractionListener {
// TODO: Update argument type and name
void onListFragmentInteraction(View view);
}
}
My main layout activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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"
tools:context=".MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/top_margin"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay"
/>
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/global_top_margin"
android:theme="#style/AppTheme.AppBarOverlay">
<TextView
android:id="#+id/fragment_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:textSize="14sp"
android:textStyle="bold" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content_main_placeholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/main_fragment_top_margin"
android:clickable="true"
android:scrollbars="vertical"
></FrameLayout>
<include layout="#layout/nav_menu_main" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#drawable/ic_action_add_entity"/>
</android.support.design.widget.CoordinatorLayout>
My fragment layout fragment_test.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"
tools:context=".MainActivity"
android:id="#+id/term_list_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
android:clickable="true">
<Button
android:id="#+id/d_button_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:text="My Button to Click"
android:focusable="true"
android:focusableInTouchMode="true"
android:clickable="true"
android:textAppearance="?android:textAppearanceLarge" />
</LinearLayout>
Ultimately I fixed my own problem. Which was started by choosing Navigation Activity when first starting my project.
I removed
<include layout="#layout/nav_menu_main" />
from my activity_main.xml then restructured it whith the xml from nav_menu_main, using DrawerLayout as the Parent and CoordinatorLayout from activity_main.xml as the child.
I consulted this stack Overflow which lead me to my fix.
Drawer Layout Overlapping | Covering complete space in Fragment
My new activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|enterAlways"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<android.support.design.widget.CoordinatorLayout
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"
tools:context=".MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/top_margin"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay"
/>
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/global_top_margin"
android:theme="#style/AppTheme.AppBarOverlay">
<TextView
android:id="#+id/fragment_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:textSize="14sp"
android:textStyle="bold" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content_main_placeholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/main_fragment_top_margin"
android:clickable="true"
android:scrollbars="vertical"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#drawable/ic_action_add_entity"/>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
I want to show bottom Sheet from top to bottom. Default BottomSheet Open From bottom to top but i want bottom sheet open form Title/Toolbar/ActionBar
I Search On google but can't find solution
This is My Code
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:id="#+id/cordinate"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.bttomsheettoptobottom.MainActivity">
<Button
android:id="#+id/btOpenBottomSheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="Show Bottom Sheet"/>
<LinearLayout
android:id="#+id/llBottomSheet"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#color/colorPrimary"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
android:orientation="vertical">
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
MainActivity.java
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private Button btOpenBottomSheet;
private CoordinatorLayout coordinatorLayout;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btOpenBottomSheet:
showBottomSheetDialog();
break;
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
btOpenBottomSheet = (Button)findViewById(R.id.btOpenBottomSheet);
btOpenBottomSheet.setOnClickListener(mOnClickListener);
}
private void showBottomSheetDialog() {
CoordinatorLayout coordinatorLayout = (CoordinatorLayout)findViewById(R.id.cordinate);
View bottomSheet = coordinatorLayout.findViewById(R.id.llBottomSheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
// React to state change
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
// React to dragging events
}
});
}
}
Create a custom TopsheetBehaviour class as shown here and make the sheet Behaviour as
<LinearLayout
android:id="#+id/llBottomSheet"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#color/colorPrimary"
app:layout_behavior="your.package.components.TopSheetBehavior"
android:orientation="vertical">
</LinearLayout>
It worked in my case. Hope it helps to you!
My requirement is i need the functionality of Navigation Drawer (Navigation Menu should appear both by clicking on the toggle icon and also dragging from margin) + Drawer layout on top of the action bar.
Check this post, i want the similar action.
I had gone through many post regarding this in SO itself, most of them saying to use a third-party library to use to get this done. But i don't want to use, instead in One SO question CommonsWare said like this can be done by tweaking the Drawerlayout.
How to achieve this?
Note: I don't want to use external library as it was creating problems.
In Android Default you cannot move the DrawerLayout along with the Action Bar. However if your are keen on using the Default Navigation Drawer. Hide the Action bar and create a Top layout similar to action bar. It will move with the drawerLayout. If you want further help code wise let me know.
Find my updated answer
MainActivity.java
package com.example.android.navigationdrawerexample;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
public class MainActivity extends FragmentActivity {
DrawerLayout drawerLayout;
ActionBarDrawerToggle drawerToggle;
ImageView menubtn, addbtn;
LinearLayout menuLayout;
RelativeLayout frame;
TranslateAnimation anim;
float moveFactor, lastTranslate = 0.0f;
ListView accList;
String[] menuValues = { "Add", "View" };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new PlaceholderFragment())
.commit();
}
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
menuLayout = (LinearLayout) findViewById(R.id.menu);
accList = (ListView) findViewById(R.id.drawer_list);
frame = (RelativeLayout) findViewById(R.id.rl_main);
menubtn = (ImageView) findViewById(R.id.menu_btn);
addbtn = (ImageView) findViewById(R.id.add_btn);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, menuValues);
accList.setAdapter(adapter);
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout,
R.drawable.ic_drawer, R.string.open, R.string.close) {
public void onDrawerClosed(View view) {
}
public void onDrawerOpened(View drawerview) {
// adapter = new AccountAdapter(this, R.layout.row_acc, values);
}
#SuppressLint("NewApi")
public void onDrawerSlide(View drawerView, float slideOffset) {
// use this code only if you need the fragment to slide over, if you want the
// drawerlayout to be above the main screen then ignore this code.
//moveFactor = (menuLayout.getWidth() * slideOffset);
//drawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
// Gravity.LEFT);
//if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// frame.setTranslationX(moveFactor);
//} else {
// anim = new TranslateAnimation(lastTranslate, moveFactor,
// 0.0f, 0.0f);
// anim.setDuration(0);
// anim.setFillAfter(true);
// frame.startAnimation(anim);
// lastTranslate = moveFactor;
//}
}
};
drawerLayout.setDrawerListener(drawerToggle);
menubtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (drawerLayout.isDrawerVisible(Gravity.LEFT)) {
return;
} else {
drawerLayout.openDrawer(Gravity.LEFT);
}
}
});
accList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (position == 0) {
// Write your code
drawerLayout.closeDrawers();
}
}
});
addbtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Toast.makeText(MainActivity.this, "Action Bar Icon code as per your requirement", Toast.LENGTH_LONG).show();
}
});
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_planet, container,
false);
return rootView;
}
}
}
activity_main.xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
tools:context=".MainActivity" >
<RelativeLayout
android:id="#+id/rl_main"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:id="#+id/top_layout"
android:layout_width="match_parent"
android:layout_height="40dp" >
<ImageView
android:id="#+id/menu_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dp"
android:src="#drawable/ic_drawer" />
<ImageView
android:id="#+id/add_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:src="#android:drawable/ic_dialog_info"/>
</RelativeLayout>
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/top_layout" />
</RelativeLayout>
<!-- The navigation drawer -->
<LinearLayout
android:id="#+id/menu"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="left"
android:background="#android:color/white"
android:orientation="vertical" >
<TextView
android:id="#+id/welcome_text"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:gravity="center_vertical"
android:text="OPEN" />
<ListView
android:id="#+id/drawer_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="20dp"
android:choiceMode="singleChoice"
android:divider="#android:color/white"
android:dividerHeight="2dp"
android:listSelector="#android:color/white" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
And another important part Please change your application theme to noActionbar. Let me know if this satisfies your requirements.
Have you checked the Navigation Drawer documentation already? You have to provide a layout for the navigation drawer anyways, so it's always custom and up to you how it looks like.