I am new in the Topic "Accessibility Services".I am able to Scroll for button clicks, and able to switch off phone and many More things,
but i want to make my layout(action_bar.xml) Movable
So,
can anybody tell me please How to Make action_bar Movable
Here is my
action_bar.xml::
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="#+id/power"
android:layout_weight="1"
android:text="#string/power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="#+id/volume_up"
android:text="#string/volume"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:layout_weight="1"
android:id="#+id/scroll"
android:text="#string/scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="#+id/swipe"
android:text="#string/swipe"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
And ActionBarService.Java ,Where i Have Used it:
#Override
protected void onServiceConnected() {
// Create an overlay and display the action bar
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.TOP;
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
wm.addView(mLayout, lp);
}
The answer by #fishbone is mostly correct, EXCEPT for the little part where overlays in Accessibility Services are NOT the same. Certainly, making this assumption simplifies things, but it is ultimately false. There are very important considerations specific to accessibility services, and In most ways they behave exactly like activities, but the ways that Accessibility Services launch overlays is very important and different from the ways most views behave, particularly in how they intercept touch events. You have to be very careful with touch events. Ultimately you want the view to be touchable, BUT NOT, take up the whole window. The two types you can play around with for this would be:
TYPE_ACCESSIBILITY_OVERLAY
or
TYPE_APPLICATION_OVERLAY
These two behave similarly, but not. The latter may help you if you're stuck on receiving touch events in your actual view.
The core problem is, that the layout parameters available for WindowManager only allow you to either completely intercept touch events or to not do so at all. You can't have it do so for this part of your view, and not for others. The logic for attempting to pass events past your window through to a window that you don't own... just don't go there.
As such, what you have to do, is NOT have a complete layout view. You have to add your view as Touchable, but have your view ONLY take up the part of the screen that it actually has to overlay. This should obviously be as minimal as possible (becuase touch events won't be able to go beind this view). THEN you'll have to do a custom hold touch listener, and do the touch and drag logic to move your view around manually.
You could potentially use the touch/drag view ONLY for replacement. As in, have a button that enables "drag mode" to replace it. And have that by the only time the entire layout is added to the window, remove the layout, and just add the smaller, non-layout version that is just your toolbar view.
Unfortunately there is no simple answer here. This is not something that Accessibility APIs are intended to do. I would also feel obligated to warn you, that the new expectations for Accessibility Services that Google is mulling around would almost certainly result in an Accessibility Service that does something like this being removed/not allowed in the Google Play Store.
Overlays work by the same rules as the usual View on the Activity or Fragment. There is no magic property such android:movable="true" that can make an overlay movable. You should make it by yourself.
Here is my example of a movable View:
action_bar.xml (Here I replace LinearLayout with custom DraggableLayout)
<?xml version="1.0" encoding="utf-8"?>
<your.package.name.DraggableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="#+id/power"
android:layout_weight="1"
android:text="Power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="#+id/volume_up"
android:text="Volume"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:layout_weight="1"
android:id="#+id/scroll"
android:text="Scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="#+id/swipe"
android:text="Swipe"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</your.package.name.DraggableLayout>
DraggableLayout.class
public class DraggableLayout extends LinearLayout implements View.OnDragListener {
GestureDetector mLongClickDetector;
Point mPickPoint;
public DraggableLayout(Context context) {
this(context, null, 0);
}
public DraggableLayout(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DraggableLayout(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// When user performs a long press, we begin dragging
mLongClickDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
public void onLongPress(MotionEvent e) {
mPickPoint = new Point((int) e.getX(), (int) e.getY());
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(DraggableLayout.this) {
#Override
public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) {
outShadowSize.set(getWidth(), getHeight());
outShadowTouchPoint.set(mPickPoint.x, mPickPoint.y);
}
};
startDrag(null, shadowBuilder, null, 0);
}
});
}
#Override
protected void onAttachedToWindow() {
// We should register this class as OnDragListener to parent view to catch DROP events from it
((ViewGroup) getParent()).setOnDragListener(this);
super.onAttachedToWindow();
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//This is also an important point: we must intercept touch events before the child elements (Buttons and so on)
return mLongClickDetector.onTouchEvent(ev);
}
#Override
public boolean onDragEvent(DragEvent event) {
if (event.getAction() == DragEvent.ACTION_DROP) {
// And when user performs drop we change position of view
setX(event.getX() - mPickPoint.x);
setY(event.getY() - mPickPoint.y);
return true;
}
return false;
}
#Override
public boolean onDrag(View v, DragEvent event) {
return onDragEvent(event);
}
}
ActionBarService.Java
#Override
protected void onServiceConnected() {
// Create an overlay and display the action bar
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT, // Overlay must be full screen otherwise my trick will not work
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // Allow another windows to receive touch events
PixelFormat.TRANSLUCENT);
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
wm.addView(mLayout, lp);
}
It seems to be working, let me know if not that.
Related
Background
I have a TabLayout with some elements in it.
In portrait mode, the elements don't have enough space to appear. So I used:
app:tabMode="scrollable"
On the other hand, in landscape mode, the elements have excess space and I want it to be centered. So I used this approach:
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
style="#style/Tab"
android:layout_width="wrap_content" <!-- Used wrap_content -->
android:layout_height="wrap_content"
android:layout_centerHorizontal="true" <!-- And CenterHorizontal -->
app:tabMode="scrollable" />
But since the background color is null in my MainActivity:
window.setBackgroundDrawable(null)
The TabLayout appears with (Black Wings) in Landscape Mode.
I want it to have #color/colorPrimary wings instead.
So I had two options:
1- Make the background of my MainActivity, not null (aka #color/colorPrimary)
I don't want to do that since all my fragments in the companion ViewPager will experience Overdraw because they all have different backgrounds set programmatically.
OR
2- Add a Container to incubate my TabLayout and set its background with my #color/colorPrimary, like so:
<RelativeLayout
android:id="#+id/tabs_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
style="#style/Tab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
app:tabMode="scrollable" />
</RelativeLayout>
I will discuss the problems of this approach below.
Problem
Using Option #2 above:
There is still a tiny bit of Overdraw where the two views, parent RelativeLayout and child TabLayout, overlap.
So how can I remove this extra bit of Overdraw?
Thoughts
I am thinking of overriding the OnDraw method in the View class to suit my needs, but the challenge is that how to know the actual positions I would need to ClipRect()
Another thought is to come up with a, you know, (simpler) approach different from Option #2 above, to solve the Background issue.
Thanks in advance.
I looked all over for an answer to this exact problem. In my case I was dynamically adding and removing tabs, so I wanted it to fill the screen when there were only a few tabs, but start scrolling when there were too many rather than shrinking them or putting the titles on two lines. Using the following custom tab layout finally got it working for me. It was key to set the minimum width before calling super.onMeasure().
public class CustomTabLayout extends TabLayout {
public CustomTabLayout(Context context) {
super(context);
}
public CustomTabLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ViewGroup tabLayout = (ViewGroup)getChildAt(0);
int childCount = tabLayout.getChildCount();
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
int tabMinWidth = displayMetrics.widthPixels/childCount;
for(int i = 0; i < childCount; ++i){
tabLayout.getChildAt(i).setMinimumWidth(tabMinWidth);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Set the tab mode to scrollable in the xml.
<com.package.name.CustomTabLayout
android:id="#+id/my_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable">
I think you don't need to wrap your TabLayout with the additional RelativeLayout
just add the background to your tabLayout like so,
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
style="#style/Tab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:layout_centerHorizontal="true"
app:tabMode="scrollable" />
I'm currently developing a simple Notes application where the user can input a title and the content of their note. What I am looking to achieve is that when the user clicks the note content (EditText) the soft keyboard comes up and only the note content EditText reduces in size (resizes) whilst everything else remains in the same position.
My current implementation can be seen below:
Manifest:
<activity android:theme="#style/AppTheme"
android:name=".AddActivity"
android:label="#string/add_record"
android:windowSoftInputMode="adjustResize"
android:parentActivityName=".MainActivity"
android:excludeFromRecents="true"/>
XML - Add Activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/add_record"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<EditText
android:id="#+id/title_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="#string/enter_title"
android:inputType="textCapSentences"
android:textColor="#color/fontPrimary"
android:theme="#style/EditTextCustomCursor">
<requestFocus />
</EditText>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/modify_scrollview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="false"
android:isScrollContainer="false"
android:fillViewport="true">
<EditText
android:id="#+id/note_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#null"
android:ellipsize="end"
android:gravity="top|left"
android:hint="#string/enter_note"
android:inputType="textCapSentences|textMultiLine"
android:paddingLeft="5dp"
android:scrollHorizontally="false"
android:textColor="#color/fontPrimary"
android:theme="#style/EditTextCustomCursor" />
</ScrollView>
</LinearLayout>
Java - Add Activity
private int screenHeight;
private int actionBarHeight = 350;
private int keyboardHeight;
...
private void setupListeners() {
final LinearLayout layout = (LinearLayout) findViewById(R.id.add_record);
layout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
layout.getWindowVisibleDisplayFrame(r);
screenHeight = layout.getRootView().getHeight();
keyboardHeight = screenHeight - (r.bottom - r.top);
Log.d("Keyboard Size", "Size: " + keyboardHeight);
}
});
KeyboardVisibilityEvent.setEventListener(
AddActivity.this,
new KeyboardVisibilityEventListener() {
#Override
public void onVisibilityChanged(boolean isOpen) {
if (isOpen) {
Log.d("KB", "openKeyboard");
scrollView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, screenHeight - actionBarHeight - keyboardHeight));
} else {
Log.d("KB", "closeKeyboard");
scrollView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
}
}
});
}
This is using the Keyboard library (https://github.com/yshrsmz/KeyboardVisibilityEvent) to detect when the keyboard is opened or closed. This works perfectly and the height / layout is adjusted just how I want it to look but only if the user clicks at the top of the EditText. If the user clicks at the bottom of the EditText (if they have entered a long note) then the whole layout gets pushed up leaving a large gap at the bottom of the page.
Therefore, is there any way how wherever in the EditText / ScrollView the user clicks, for it to only adjust that one EditText in height and leave the other EditText in place at the top of the screen without pushing it and the SupportActionBar out of view? Also, the ScrollView is being used to achieve the vertical scrollbar on the right side of the screen - if this same behaviour can be achieved using just the EditText, then I would remove the ScrollView altogether.
EDIT - Add Photos
Image 1: Long note content (bottom of note content is at the bottom of the scrollView (which cannot be seen, until scrolled))
Image 2: Same note but clicking at the bottom, forces the top EditText and Support ActionBar out of view whilst leaving a gap at the bottom.
Explanation: Where the F is highlighted (in Image 2) that is the bottom of the EditText / ScrollView so you can see the large gap created between the top of the soft keyboard and the bottom of the EditText / ScrollView
Desired behaviour: Clicking anywhere in the bottom EditText should only resize that particular EditText to make room for the soft keyboard and ensure that this EditText is above the soft keyboard so the user can see what they are typing whilst the top EditText remains in the same position throughout.
Its because you're adding edittext in a scroll view. why do you even need scroll view? scroll view have a property of going to specific line when keyboard pop-up which is causing this behavior. if you really want to use scrollview, then add master layout as scrollview. add one direct child aka linear layout in there and add all the content in that linear layout.
I have managed to resolve most of this by doing the following:
Removing the ScrollView
Subclassing EditText (to receive the close keyboard button)
Adding a height-change listener
Adding the scroll bars property to the EditText
Manifest:
<activity android:theme="#style/AppTheme"
android:name=".AddActivity"
android:label="#string/add_record"
android:windowSoftInputMode="adjustNothing"
android:parentActivityName=".MainActivity"
android:excludeFromRecents="true"/>
XML - Add Activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/add_record"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:windowSoftInputMode="stateHidden">
<EditText
android:id="#+id/title_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="#string/enter_title"
android:inputType="textCapSentences"
android:textColor="#color/fontPrimary"
android:theme="#style/EditTextCustomCursor">
<requestFocus />
</EditText>
<com.securenotes.ExtendedEditText
android:id="#+id/note_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#null"
android:ellipsize="end"
android:gravity="top|left"
android:hint="#string/enter_note"
android:inputType="textCapSentences|textMultiLine"
android:lines="50"
android:maxLines="20"
android:minLines="5"
android:paddingLeft="5dp"
android:scrollHorizontally="false"
android:scrollbars="vertical"
android:textColor="#color/fontPrimary"
android:theme="#style/EditTextCustomCursor" />
</LinearLayout>
Java - Add Activity:
private Boolean initialStart = true;
private Boolean isOpened = false;
...
private void setupListeners() {
final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
Log.d("KB", "HeightDiff: " + heightDiff);
if (heightDiff > 100) { // 99% of the time the height diff will be due to a keyboard.
if (!isOpened && initialStart) {
Log.d("KB", "1) openKeyboard");
//Do two things, make the view top visible and the editText smaller
noteEditText.setLines(15);
noteEditText.requestLayout();
initialStart = false;
isOpened = true;
} else if (!isOpened && noteEditText.hasFocus()) {
Log.d("KB", "2) openKeyboard");
//Do two things, make the view top visible and the editText smaller
noteEditText.setLines(15);
noteEditText.requestLayout();
isOpened = true;
}
}
}
});
noteEditText.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d("KB", "EditText onClick");
isOpened = false;
}
});
noteEditText.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Log.d("KB", "closeKeyboard");
noteEditText.setLines(50);
noteEditText.requestLayout();
}
return false;
}
});
}
Java - Subclassed EditText:
public class ExtendedEditText extends EditText {
public ExtendedEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ExtendedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExtendedEditText(Context context) {
super(context);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
dispatchKeyEvent(event);
return false;
}
return super.onKeyPreIme(keyCode, event);
}
}
However, the one remaining issue is that if the user is scrolling the EditText, sometimes it detects it as a click rather than a scroll so the keyboard is then made visible and the layout (number of lines) is changed. I looked into the onScrollChangeListener but this requires API 23 and my current minimum is 15 - is there any way around this to tell the difference between a scroll and an actual click on the EditText?
I am using the Support Library to add a bottom bar similar to the material design one. The bottom bar works great but it seems that if I have the bar displayed, if I try to open any fragment from my custom adapter, the fragment does not open...or maybe it opens behind my main layout? I have no idea how to figure this out. Below is my code.
I've read more posts on SO and around the web and I think this is related to the fragment being properly loaded but below or next to the bottom bar...and that is why it isn't visible? Why does this happen? Is it because the bottom bar has a LinearLayout? I defined it as a menu so I'm not sure if I can control it being a LinearLayout....
Setting up the bottom bar, this method is called from the onCreate of my activity:
public void setupBottomToolbar(Bundle savedInstanceState) {
mBottomBar = BottomBar.attach(MainActivity.this, savedInstanceState);
mBottomBar.setItems(R.menu.bottombar_menu);
mBottomBar.setOnMenuTabClickListener(new OnMenuTabClickListener() {
#Override
public void onMenuTabSelected(#IdRes int menuItemId) {
if (menuItemId == R.id.toolbar_jobs) {
} else if (menuItemId == R.id.toolbar_messages) {
} else if (menuItemId == R.id.toolbar_recentJobs) {
} else if (menuItemId == R.id.toolbar_employerPools) {
}
}
#Override
public void onMenuTabReSelected(#IdRes int menuItemId) {
if (menuItemId == R.id.toolbar_jobs) {
// The user reselected item number one, scroll your content to top.
} else if (menuItemId == R.id.toolbar_messages) {
} else if (menuItemId == R.id.toolbar_employerPools) {
} else if (menuItemId == R.id.toolbar_recentJobs) {
}
}
});
// Setting colors for different tabs when there's more than three of them.
// You can set colors for tabs in three different ways as shown below.
mBottomBar.getBar().setBackgroundColor(getResources().getColor(R.color.laborswipe_darkgray));
mBottomBar.setActiveTabColor(getResources().getColor(R.color.laborswipe_lightgray));
// Make a Badge for the second tab, with red background color and a value of "13".
BottomBarBadge unreadMessages = mBottomBar.makeBadgeForTabAt(1, getResources().getColor(R.color.laborswipe_orange), 5);
// Control the badge's visibility
unreadMessages.show();
//unreadMessages.hide();
// Change the displayed count for this badge.
//unreadMessages.setCount(4);
// Change the show / hide animation duration.
unreadMessages.setAnimationDuration(200);
// If you want the badge be shown always after unselecting the tab that contains it.
unreadMessages.setAutoShowAfterUnSelection(true);
// If you don't want this badge to be hidden after selecting the tab contains it.
unreadMessages.setAutoShowAfterUnSelection(false);
}
In my adapter, I am trying to open the fragment when you click a button, like this:
holder.desc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "Open Description", Toast.LENGTH_SHORT).show();
JobDescFragment firstFragment = new JobDescFragment();
((MainActivity)context).getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
});
If I comment out the call to setupBottomToolbar() in my onCreate of the activity, the fragment opens up fine...but that means I don't have the bottom bar...
What am I missing? There has to be a way to use the bottom bar and also open a fragment?
Thanks!
EDIT:
Here is the top part of my activity.
public class MainActivity extends AppCompatActivity {
private ArrayList<String> swipecardsList;
private ArrayList<Job> jobList = new ArrayList<Job>();
private JobAdapter arrayAdapter; //arrayadapter
private BottomBar mBottomBar;
SharedPreferences settings;
#InjectView(R.id.frame) SwipeFlingAdapterView flingContainer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remove title bar
//this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//color the notification bar with our company colors
Window window = this.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setStatusBarColor(this.getResources().getColor(R.color.laborswipe_notificationbar));
//remove title from action bar and add the logo to the top left of the action bar
setupTopToolbar();
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
//set up the bottom toolbar using the roughike library to mimic android material design
setupBottomToolbar(savedInstanceState);
My adapter:
public class JobAdapter extends ArrayAdapter<Job> {
private final Context context;
private final ArrayList<Job> jobs;
private final int layoutResourceId;
private final SwipeFlingAdapterView flingContainer;
private boolean isExpanded = false;
public JobAdapter(Context context, int layoutResourceId, ArrayList<Job> jobs, SwipeFlingAdapterView flingContainer) {
super(context, layoutResourceId, jobs);
this.context = context;
this.jobs = jobs;
this.layoutResourceId = layoutResourceId;
this.flingContainer = flingContainer;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
final ViewHolder holder;
String pay, hrs;
final Bundle fragmentParams = new Bundle();
LayoutInflater inflater = LayoutInflater.from(context);
if (view == null) {
view = inflater.inflate(layoutResourceId, parent, false);
holder = new ViewHolder();
holder.title = (TextView)view.findViewById(R.id.tv_jobTitle);
holder.desc = (TextView) view.findViewById(R.id.tv_JobDesc);
view.setTag(holder);
} else {
holder = (ViewHolder)view.getTag();
}
Job j = jobs.get(position);
holder.title.setText(j.getJobTitle());
holder.desc.setText(j.getDescription());
//when user clicks apply, swipe the card right
holder.apply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Open up a fragment to display the entire job description
Toast.makeText(context, "Applied", Toast.LENGTH_SHORT).show();
flingContainer.getTopCardListener().selectRight();
}
});
//when user clicks dismiss, swipe the card left
holder.dismiss.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Open up a fragment to display the entire job description
Toast.makeText(context, "Dismissed", Toast.LENGTH_SHORT).show();
flingContainer.getTopCardListener().selectLeft();
}
});
//on click event listener for the job description field - open larger window to read description
holder.desc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Toast.makeText(context, "Open Description", Toast.LENGTH_SHORT).show();
JobDescFragment firstFragment = new JobDescFragment();
Fragment frag = new Fragment();
frag = firstFragment.newJobDescFrag(j.getDescription());
((MainActivity) context).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, frag)
.addToBackStack("JobDesc").commit();
}
});
return view;
}
public class ViewHolder
{
TextView title;
TextView payrate;
TextView dateRange;
TextView workinghrs;
TextView location;
TextView companyname;
TextView desc;
TextView experience;
TextView equipment;
Button apply, dismiss, expand;
}
}
activity_main.xml:
<merge
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">
<com.lorentzos.flingswipe.SwipeFlingAdapterView
android:id="#+id/frame"
android:background="#color/laborswipe_lightgray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".MainActivity"
android:layout_gravity="top" />
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</merge>
Fragment Layout:
<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=".JobDescFragment">
<LinearLayout
android:id="#+id/outerDescriptionLayout"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_gravity="center_horizontal|top"
android:orientation="vertical"
android:background="#drawable/swipecard_shadow"
android:gravity="top"
android:layout_marginLeft="5dp">
<LinearLayout
android:id="#+id/DescriptionLayout"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_gravity="center_horizontal|top"
android:orientation="vertical"
android:weightSum="1"
android:gravity="top"
android:layout_marginTop="20dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="#00FF00"
android:clickable="true">
<TextView
android:layout_width="200dp"
android:layout_height="200dp"
android:text="Detailed Description:"
android:textColor="#000000"
android:id="#+id/tv_title" />
<TextView
android:layout_width="200dp"
android:layout_height="200dp"
android:text="THIS IS THE FULL DESCRIPTION"
android:textColor="#000000"
android:id="#+id/tv_fullDescription" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
Logcat:
08-07 11:20:47.799 13896-13896/com.lorentzos.swipecards.example I/System.out: DEBUG: job desc fragment loaded!
08-07 11:20:47.855 13896-13941/com.lorentzos.swipecards.example W/EGL_emulation: eglSurfaceAttrib not implemented
08-07 11:20:47.855 13896-13941/com.lorentzos.swipecards.example W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xaaa7f880, error=EGL_SUCCESS
08-07 11:20:48.002 13896-13941/com.lorentzos.swipecards.example V/RenderScript: 0xa1408000 Launching thread(s), CPUs 2
08-07 11:20:49.798 13896-13941/com.lorentzos.swipecards.example E/Surface: getSlotFromBufferLocked: unknown buffer: 0xae433ca0
When I use the bottom bar (not working- no fragment opened but toast displayed):
When I don't use the bottom bar (workin-fragment opened, background is green):
try to link a pic of problem and without problem(no bottombar) and since you are using merge the layout hierarchy will be laid off according to your activity's viewgroup(linear,relative) constraints(we don't know what they are like).
as you said when there is no bottombar ,you fragment displays perfectly though when the bottombar it there ,problem stats ,as per your log in fragment indicating that your fragment is loading perfectly even though when bottombar is visible mean fragment is there but is not visible ,seems like your fragment didn't get the appropriate space to get displayed.
other solution can be adding bottom bar to your fragment instead of activity to avoid any overlapping ,like
mBottomBar.attach(findViewById(R.id.fragmentContainer), savedInstanceState);
OK, I think the solution for this should be simple, from what I can see in your code, you are attaching the BottomBar to your activity, I think this is the problem. If you were to read the readme.md in the roughike/BottomBar github page you'd find this
Why is it overlapping my Navigation Drawer?
All you need to do is instead of attaching the BottomBar to your Activity, attach it to the view that has your content. For example, if your fragments are in a ViewGroup that has the id fragmentContainer, you would do something like this:
mBottomBar.attach(findViewById(R.id.fragmentContainer), savedInstanceState);
So, since navigation drawer works with transition a fragment in and out of view with animation, the same thing is happening when you are adding a new fragment to your activity.
The Solution
From what I can see in your code, your fragment container id is this: fragment_container in your activity layout. So according to the documentation you'd just need to do attach your bottomBar to the fragment_container instead of MainActivity.this
mBottomBar.attach(findViewById(R.id.fragment_container), savedInstanceState);
If the above doesn't work try this
What you'd need to do is add an extra FrameLayout to hold your bottombar, which has a transparent background, but is on top of your fragment.
So change your main_activity layout to
<merge
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">
<com.lorentzos.flingswipe.SwipeFlingAdapterView
android:id="#+id/frame"
android:background="#color/laborswipe_lightgray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".MainActivity"
android:layout_gravity="top" />
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/holder_bottombar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"/>
</merge>
Now in the code instead of attaching the bottom bar to mainactivity, just attach it to the holder like so
mBottomBar.attach(findViewById(R.id.holder_bottombar), savedInstanceState);
I have made a transparent custom progress bar.I want to move the progress bar to a certain location on the screen programatically.But every time the custom progress bar get drawn at the middle of the screen.
public class CustomProgressBar extends Dialog {
ProgressBar mProgressBar;
TextView mTextMessage;
public CustomProgressBar(Context context, int id) {
super(context, R.style.ProgressDialogTheme);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.custom_progree_dialog,
null);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);//the progress bar does not get aligned to left top with the defined margin space.
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);//
params.setMargins(50, 50, 0, 0);//
// layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, id);
this.addContentView(view, params);
}
}
And this is how I am using it inside my activity
Dialog mProgressBar = new CustomProgressBar(
MyActivity.this,
otherView.getId());
My progress bar layout file custom_progree_dialog.xml
<?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="wrap_content" >
<ProgressBar
android:id="#+id/id_server_connection_progress_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateDrawable="#drawable/somedrwablefile" />
<TextView
android:id="#+id/id_server_connection_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="#dimen/padding_30px"
android:layout_marginTop="#dimen/padding_4px"
android:layout_toRightOf="#id/progress_dialog"
android:text="#string/connectingMessage"
android:textColor="#color/white"
android:textSize="#dimen/padding_40px" />
</RelativeLayout>
Please guide me and let me know where I am going wrong.I have spent two days trying to figure out the problem.
So I solved this problem by making changes to my custom_progress_dialog and aligning the progress bar and the text to the location I want.Also I am not using the custom class any more.I am just inflating the layout at runtime and adding it as a child view inside my activity.
if (mView == null)
{
mView = getLayoutInflater().inflate(R.layout.server_connection_progree_dialog,null);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);
MyActivity.this.addContentView(mView, layoutParams);
}
else
if (!mView.isShown())
{
mView.setVisibility(View.VISIBLE);
}
What I have is a canvas that takes up nearly all of the screen, then under that I want a row of buttons and some other widgets. So I did this.
XML Code
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="#+id/myLayout"
android:orientation="vertical"
android:layout_height="match_parent" >
<com.zone.manager.Tab3
android:id="#+id/tab3_display"
android:layout_width="fill_parent"
android:layout_height="620dp" />
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="match_parent" >
<Button
android:id="#+id/addZone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Zone" />
<Button
android:id="#+id/helpZone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Help" />
<SeekBar
android:id="#+id/seekBar1"
android:paddingTop="9dp"
android:layout_width="179dp"
android:layout_height="wrap_content" />
</LinearLayout>
Java Code
public class Tab3 extends View implements OnTouchListener, OnClickListener {
public Tab3(Context context, AttributeSet attrs) {
View parent = (View) getParent();
addZone = (Button) parent.findViewById(R.id.addZone);
addZone.setOnClickListener(this);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
. . . draws a bunch of stuff
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.addZone:
String w = "W~20~0~0~0~0~0";
Log.d("ZoneSize", "Zone set");
MyApplication.preferences.edit().putString( "ZoneSize", w ).commit();
MyApplication.preferences.edit().putBoolean("ZoneSizeReady", true).commit();
break;
}
}
However my problem with this is that I believe the code is not reconising where the addZone is. Because when I have the addZone.setOnClickListener active my program will crash, but when I don't have it active the layout looks like how I want it. What must I do to fix this?
addZone = (Button) findViewById(R.id.addZone);
addZone will be null because com.zone.manager.Tab3 does not have any children
So it is obvious that your code will crash
So either you will give com.zone.manager.Tab children which require also to change the base class from View to ViewGroup,
or you start with com.zone.manager.Tab parent. Something like
View parent = (View) getParent ();
addZone = (Button) parent.findViewById(R.id.addZone);
i have some tips which will make you avoid such weird bugs and others:
the code of the custom view relies on an xml layout that uses the custom view .
this is bad coding.
instead, you should use LayoutInflater , use a layout xml file for the custom view for it , and then do the "findViewById" and add the clickListeners to any view inside that you wish.
i think it's also wrong to set the custom view to hold the click listener of the other views without checking which of them was clicked . either add a check , or add a different listener for each of them (which i personally prefer) .