n this tutorial, we will create an example to customize ActionBar with a custom layout in Android. Before we begin, I assume you already have created an Android application. BELOW THERE IS FULL SOURCE CODE |
1. Main layout file:
*** android.support.v7.widget.Toolbar will be replaced by our custom action bar |
<?xml version="1.0" encoding="utf-8"?> <!-- Use DrawerLayout as root container for activity --> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <!-- Layout to contain contents of main body of screen (drawer will slide over this) --> <FrameLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#fff"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="#FF4081" android:theme="@style/ThemeOverlay.AppCompat.ActionBar" /> </FrameLayout> <!-- Container for contents of drawer - use NavigationView to make configuration easier --> <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:menu="@menu/navigation" app:headerLayout="@layout/nav_header" /> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" tools:context="pkm.com.customTitleBar.MainActivity" android:paddingTop="60dp"> <ScrollView style="@android:style/Widget.ScrollView" android:layout_width="match_parent" android:layout_height="0dip" android:layout_gravity="top" android:layout_weight="1" android:fillViewport="false" android:scrollbarStyle="insideInset"> <LinearLayout android:id="@+id/mainLayoutScrollView" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> </LinearLayout> </ScrollView> <LinearLayout android:id="@+id/mainViewBottomBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="20dp" android:orientation="vertical"> </LinearLayout> </LinearLayout> </android.support.v4.widget.DrawerLayout> |
2. Sample AndroidManifest.xml *** Turned off default action bar using > android:theme="@style/AppTheme.NoActionBar" |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="pkm.com.customTitleBar"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> |
*** android:theme="@style/AppTheme.NoActionBar" is defined in RES/VALUES/STYLES.XML as BELOW |
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="AppTheme.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> </style> </resources> |
3. Below is navigation.xml used in our main layout file: |
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/navigation_home" android:icon="@drawable/ic_home_black_24dp" android:title="@string/title_home" /> <item android:id="@+id/navigation_dashboard" android:icon="@drawable/ic_dashboard_black_24dp" android:title="@string/title_dashboard" /> <item android:id="@+id/navigation_notifications" android:icon="@drawable/ic_notifications_black_24dp" android:title="@string/title_notifications" /> </menu> |
4. Below is nav_header.xml used in our main layout: |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="80dp" android:background="?attr/colorPrimaryDark" android:padding="16dp" android:theme="@style/ThemeOverlay.AppCompat.Dark" android:orientation="vertical" android:gravity="bottom"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/app_name" android:textAppearance="@style/TextAppearance.AppCompat.Body1"/> </LinearLayout> |
5. Below is main title bar we using in our app: |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/title_text" android:layout_width="match_parent" android:layout_height="50dp" android:layout_alignParentStart="true" android:textAllCaps="true" android:text="@string/app_name" android:textAppearance="?android:attr/textAppearanceLarge" android:textColor="#fff" android:textStyle="bold" android:layout_marginStart="0dp" android:padding="10dp" android:paddingEnd="0dp" android:layout_marginEnd="85dp" android:background="@drawable/border" /> <ImageView android:id="@+id/imageView1" android:layout_width="35dp" android:layout_height="35dp" android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:layout_marginEnd="45dp" android:src="@drawable/ic_drawer_menu" /> <ImageButton android:id="@+id/imageButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:layout_marginEnd="8dp" android:background="@null" android:src="@android:drawable/ic_menu_rotate" /> </RelativeLayout> |
6. Below is our main activity class: |
package pkm.com.customTitleBar; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; public class MainActivity extends AppCompatActivity { private DrawerLayout mDrawerLayout = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); mDrawerLayout = findViewById(R.id.drawer_layout); NavigationView navigationView = findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener( new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem menuItem) { // set item as selected to persist highlight menuItem.setChecked(true); // close drawer when item is tapped mDrawerLayout.closeDrawers(); // Add code here to update the UI based on the item selected // For example, swap UI fragments here return true; } }); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar actionbar = getSupportActionBar(); //actionbar.setDisplayHomeAsUpEnabled(true); //actionbar.setHomeAsUpIndicator(R.drawable.ic_drawer_menu); Drawable drawable= getResources().getDrawable(R.drawable.ic_drawer_menu); Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); Drawable newDrawable = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, 120, 120, true)); newDrawable.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP); actionbar.setDisplayHomeAsUpEnabled(true); actionbar.setHomeAsUpIndicator(newDrawable); View v = getLinearLayoutById(R.layout.main_title_bar); actionbar.setCustomView(v); actionbar.setDisplayShowCustomEnabled(true); } public View getLinearLayoutById(int id) { LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); return inflater.inflate(id, null); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: mDrawerLayout.openDrawer(GravityCompat.START); return true; } return super.onOptionsItemSelected(item); } } |
|
CLICK HERE TO DOWNLOAD FULL EXAMPLE |
Friday, October 26, 2018
Android: ActionBar (Top Title Bar) with Custom View (Using Custom Layout as App Title) Example with Top Navigation View Example
Thursday, October 25, 2018
Android: Get linearLayout (Any layout file from layout folder by name) and add to current Layout
In need to get a LinearLayout (Any layout file from layout folder by name) and add to current Layout |
package com.pritom; import android.content.Context; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; public class TestActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.home_main_page); LinearLayout mainLayout = this.findViewById(R.id.mainLayoutScrollView); /* If you want to remove all views from current layout */ if (mainLayout.getChildCount() > 0) mainLayout.removeAllViews(); LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); /* There must be a layout file named 'home_content.xml' in layout folder */ View view = inflater.inflate(R.layout.home_content, null); mainLayout.addView(view); } } |
Saturday, October 6, 2018
Android Activity as a dialog popup box
Let say I have an Activity named PasswordCreatePage which has child dialogs as well. Now, I want to display this activity as a dialog for another activity. At this stage we need something special to do. First let see PasswordCreatePage class below: |
package com.pritom.kumar; import android.app.Activity; import android.os.Bundle; import android.view.ViewGroup; import android.view.Window; public class PasswordCreatePage extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // If you want to hide title bar this.requestWindowFeature(Window.FEATURE_NO_TITLE); // Setting dialog box title setTitle(R.string.set_password); // Setting layout page at this stage setContentView(R.layout.password_create_page); // If you want to finish this activity on touch outside of this dialog this.setFinishOnTouchOutside(false); // Setting dialog box width 100% and height as content height getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } } |
Now we will create/modify a theme in PROJECT/RES/VALUES named STYLES.XML, add below content to the file (actually this file describes the style of the dialog box): |
<style name="AlertDialogCustomWithTitle" parent="@android:style/Theme.Dialog"> <item name="android:buttonStyle">@style/ButtonColor</item> </style> |
At this stage we will create a layout page with below content (it's actually a simple layout page): |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/constraintLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_gravity="center" android:padding="10dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/password" /> </LinearLayout> |
Now we will put an entry to ANDROIDMANIFEST.XML related to our Activity: |
<activity android:name=".PasswordCreatePage" android:theme="@style/AlertDialogCustomWithTitle" android:excludeFromRecents="true"> </activity> |
We are done. If you open this activity, this will open as a Dialog Popup Box. |
Friday, October 5, 2018
Android: Last line of textview getting cut off / getting hide some parts of text view in LinearLayout
I have a horizontal LinearLayout containing a Checkbox followed by a TextView next to it. This LinearLayout is dynamically inflated multiple times in a fixed vertical LinearLayout contained within a RelativeLayout. |
The problem is the last line of the TextView gets cut in half. This happens when the dynamic text is long and spans more than one row. Below is my xml portion which causing the problem: |
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <CheckBox android:id="@+id/cbAllowTransferOnlyWifi" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_gravity="fill" android:text="@string/transfer.over.wifi.only" /> </LinearLayout> |
The solution is to appliy a LayoutGravity to the TextView item like below: |
android:layout_gravity="fill" |
And this is the fix. |
Google Drive REST API V3 > Root listing > Google Drive REST API V3 Getting Root Folder Id > List of Files & Folders From Root Directory
My target to listing all files of 'My Drive', but only the files and folders which are immediately below, not all the ones in the Drive at once. It's easy with REST API V3, below is a full code snippet to get listing of files and folders from ROOT FOLDER |
package com.pkm; import java.io.*; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.HashMap; import java.util.List; import java.util.Map; import sun.misc.BASE64Encoder; import com.google.gson.Gson; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; /** * Created by [PRITOM KUMAR] on 05-Oct-18. */ public class GoogleDriveRestApiV3 { public static void main(String[] args) throws Exception { /* I assumed you already have ACCESS TOKEN */ String AUTH_TOKEN = "ya29.GlwtBm__"; String FIELDS = "nextPageToken,files(id,name,mimeType,trashed,size,quotaBytesUsed)"; String QUERY = URLEncoder.encode( "'root' in parents " + "and trashed = false", "UTF-8" ); String URI = "https://www.googleapis.com/drive/v3/files?" + "fields=" + FIELDS + "&q=" + QUERY + "&access_token=" + AUTH_TOKEN; Map result = HttpJavaClient.doGet(URI); System.out.println(result); File outputFile = (File) result.get("outputFile"); if (outputFile != null) { String output = ""; List<String> lines = Files.readAllLines(outputFile.toPath(), Charset.defaultCharset()); for (String line : lines) { output = output + line; } Gson gson = new Gson(); Map data = gson.fromJson(output, Map.class); System.out.println(data); List<Map> files = (List<Map>) data.get("files"); for (Map map : files) { System.out.println(map); } } } public static String base64Encode(byte[] data) { BASE64Encoder base64Encoder = new BASE64Encoder(); return base64Encoder.encodeBuffer(data); } } class HttpJavaClient { public static enum Method { GET, POST, PUT, PATCH, DELETE } public static enum Type { XML, JSON, URL_ENCODED, HTTP; } public static Map doGet(String url) { return execute(url, Method.GET, "", Type.URL_ENCODED, null, null); } public static Map doPost(String url, String data, Type type, Map headers) { return execute(url, Method.POST, data, type, headers, null); } private static Map execute(String requestURL, Method requestMethod, String requestData, Type dataType, Map headers, Integer timeOutMilli) { String httpResponse = "", responseMessage = ""; Integer httpCode = 0; timeOutMilli = timeOutMilli == null ? 1000 * 30 : timeOutMilli; /* Default read & write timeout */ Map r = new HashMap(); HttpsURLConnection connection = null; try { String contentType = "", accept = "", contentLength = "" + requestData.length(); switch (dataType) { case XML: contentType = "text/xml; charset=utf-8"; accept = "text/xml"; break; case JSON: contentType = "application/json"; break; case URL_ENCODED: contentType = "application/x-www-form-urlencoded"; break; } connection = (HttpsURLConnection) new URL(requestURL).openConnection(); connection.setRequestMethod(requestMethod.name()); connection.setConnectTimeout(timeOutMilli); connection.setReadTimeout(timeOutMilli); connection.setRequestProperty("Pragma", "no-cache"); if (headers != null && headers.size() > 0) { for (Object name : headers.keySet().toArray()) { if (name.toString().endsWith("tls")) { //headers.put("tls", "TLSv1.2"); //headers.put("tls", "TLSv1"); SSLContext sc = SSLContext.getInstance(headers.get(name.toString()).toString()); sc.init(null, null, new java.security.SecureRandom()); connection.setSSLSocketFactory(sc.getSocketFactory()); } else { connection.setRequestProperty(name.toString(), headers.get(name.toString()).toString()); } } } if (requestData.length() > 0) { connection.setDoInput(true); connection.setDoOutput(true); if (accept.length() > 0) { connection.setRequestProperty("Accept", accept); } if (contentType.length() > 0) { connection.setRequestProperty("Content-Type", contentType); } connection.setRequestProperty("Content_length", contentLength); OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); writer.write(requestData); writer.flush(); writer.close(); } httpCode = connection.getResponseCode(); responseMessage = connection.getResponseMessage(); if (httpCode >= 200 && httpCode <= 299) { String responseContentType = connection.getContentType(); if (responseContentType == null || responseContentType.length() == 0) { responseContentType = "txt"; } else { if (responseContentType.contains(";")) { responseContentType = responseContentType.substring(0, responseContentType.indexOf(";")); } if (responseContentType.contains("text/html")) { responseContentType = "html"; } else if (responseContentType.contains("image/")) { responseContentType = "image"; } else if (responseContentType.contains("/")) { String[] parts = responseContentType.split("/"); responseContentType = parts[parts.length - 1]; } } Map<String, List<String>> map = connection.getHeaderFields(); for (Map.Entry<String, List<String>> entry : map.entrySet()) { System.out.println("Key=" + entry.getKey() + " ,Value=" + entry.getValue()); } System.out.println("Key=ResponseType ,Value=" + responseContentType); File tempFile = File.createTempFile("hello", ".tmp"); RandomAccessFile output = new RandomAccessFile(tempFile, "rw"); InputStream is = connection.getInputStream(); BufferedInputStream input = new BufferedInputStream(is); Integer fileLength = connection.getContentLength(); int readSize = 1024, downloadedSize = 0; byte data[] = new byte[readSize]; int count = 0; int progress = 0; Long timeNeeded = System.currentTimeMillis(); while ((count = input.read(data, 0, readSize)) >= 0 && progress != 100) { downloadedSize += count; output.write(data, 0, count); progress = (int) ((downloadedSize * 100) / fileLength); Long mb = output.length() / (1024 * 1024); System.out.println("PROGRESS = " + (progress) + "%, DOWNLOADED=" + mb + " MB, TYPE=" + responseContentType); } output.close(); input.close(); r.put("outputFile", tempFile); timeNeeded = (System.currentTimeMillis() - timeNeeded) / 1000; System.out.println("TIME REQUIRED=" + timeNeeded + " SECONDS!!!"); } } catch (Exception ex) { httpResponse = ""; responseMessage = ex.getMessage(); } finally { try { connection.disconnect(); } catch (Exception ex10) { } } r.put("code", httpCode); r.put("message", responseMessage); r.put("output", httpResponse); return r; } } |
Below is output of above example: |
Key=null ,Value=[HTTP/1.1 200 OK] Key=X-Frame-Options ,Value=[SAMEORIGIN] Key=Alt-Svc ,Value=[quic=":443"; ma=2592000; v="44,43,39,35"] Key=Vary ,Value=[X-Origin, Origin] Key=Date ,Value=[Fri, 05 Oct 2018 12:26:57 GMT] Key=Content-Length ,Value=[737] Key=X-XSS-Protection ,Value=[1; mode=block] Key=Expires ,Value=[Fri, 05 Oct 2018 12:26:57 GMT] Key=Content-Type ,Value=[application/json; charset=UTF-8] Key=Server ,Value=[GSE] Key=X-Content-Type-Options ,Value=[nosniff] Key=Cache-Control ,Value=[private, max-age=0, must-revalidate, no-transform] Key=ResponseType ,Value=json PROGRESS = 100%, DOWNLOADED=0 MB, TYPE=json TIME REQUIRED=0 SECONDS!!! {message=OK, outputFile=C:\Users\HP\AppData\Local\Temp\hello8652555977765600581.tmp, code=200, output=} {files=[{id=1KRehy6fX-6WwWi4AAERUklXki8EqwoWh, name=Mine.txt, mimeType=text/plain, trashed=false, size=7, quotaBytesUsed=7}, {id=12EC7CqD4gY3w9SGefvpO_VQQubWGZ_Vb, name=CORE-ITEMS, mimeType=application/vnd.google-apps.folder, trashed=false, quotaBytesUsed=0}, {id=1rGwUE6XV2hfmv0NamUI-sfpdSSERdZ0j, name=[RePack] Full Version Game.zip, mimeType=application/x-zip-compressed, trashed=false, size=4832867859, quotaBytesUsed=4832867859}]} {id=1KRehy6fX-6WwWi4AAERUklXki8EqwoWh, name=Mine.txt, mimeType=text/plain, trashed=false, size=7, quotaBytesUsed=7} |
Subscribe to:
Posts (Atom)